Import Data

corrcounts_merge <- readRDS("~/VersionControl/senescence_benchmarking/Data/corrcounts_merge.rds")
metadata_merge <- readRDS("~/VersionControl/senescence_benchmarking/Data/metadata_merge.rds")
SenescenceSignatures <- readRDS("~/VersionControl/senescence_benchmarking/CommonFiles/SenescenceSignatures_divided_newCellAge.RDS")
set.seed("123456")
metadata_merge_corr <- metadata_merge
metadata_merge_corr$random_cat <-  sample(c("A","B","C"), nrow(metadata_merge_corr), replace = T)
metadata_merge_corr$random_numeric <- sample(0:100, nrow(metadata_merge_corr), replace = TRUE)
metadata_merge_corr$Is_Senescent <- ifelse(metadata_merge_corr$Condition == "Senescent", "Senescent", "Non Senescent")
library(markeR)
library(ggplot2)
library(ggpubr)
library(edgeR)
?markeR

Scores

?CalculateScores
ℹ Rendering development documentation for "CalculateScores"

Unidirectional

df_ssGSEA <- CalculateScores(data = corrcounts_merge, metadata = metadata_merge, method = "ssGSEA", gene_sets = SenescenceSignatures)
Considering unidirectional gene signature mode for signature [DOWN]_CellAge
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature [DOWN]_HernandezSegura
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature [DOWN]_SeneQuest
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature [UP]_CellAge
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature [UP]_HernandezSegura
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature [UP]_SeneQuest
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature CSgene
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature REACTOME_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature SAUL_SEN_MAYO
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
senescence_triggers_colors <- c(
  "none" = "#E57373",  # Soft red  
  "Radiation" = "#BDBDBD",  # Medium gray  
  "DNA damage" = "#64B5F6",  # Brighter blue  
  "Telomere shortening" = "#4FC3F7",  # Vivid sky blue  
  "DNA demethylation" = "#BA68C8",  # Rich lavender  
  "Oxidative stress" = "#FDD835",  # Strong yellow  
  "Conditioned Medium" = "#F2994A",  # Warm orange  
  "Oncogene" = "#81C784",  # Medium green  
  "Lipid Accumulation" = "#E57373",  # Coral  
  "Calcium influx" = "#26A69A",  # Deep teal  
  "Plasma membrane dysruption" = "#D32F2F",  # Strong salmon  
  "OSKM factors" = "#FFB74D",  # Bright peach  
  "YAP KO" = "#9575CD"  # Deep pastel purple  
)

cellTypes_colors <- c(
  "Fibroblast" = "#FF6961",   # Strong Pastel Red  
  "Keratinocyte" = "#FFB347", # Strong Pastel Orange  
  "Melanocyte" = "#FFD700",   # Strong Pastel Yellow  
  "Endothelial" = "#77DD77",  # Strong Pastel Green  
  "Neuronal" = "#779ECB",     # Strong Pastel Blue  
  "Mesenchymal" = "#C27BA0"   # Strong Pastel Purple  
)

cond_cohend <- list(A=c("Senescent"), # if no variable is defined, will be the first that appears in the ggplot
                    B=c("Proliferative","Quiescent"))

PlotScores(ResultsList = df_ssGSEA, ColorVariable = "CellType", GroupingVariable="Condition",  method ="ssGSEA", ColorValues = cellTypes_colors, ConnectGroups=TRUE, ncol = 6, nrow = 2, widthTitle=20, y_limits = NULL, legend_nrow = 2,cond_cohend=cond_cohend)

df_logmedian <- CalculateScores(data = corrcounts_merge, metadata = metadata_merge, method = "logmedian", gene_sets = SenescenceSignatures)

senescence_triggers_colors <- c(
  "none" = "#E57373",  # Soft red  
  "Radiation" = "#BDBDBD",  # Medium gray  
  "DNA damage" = "#64B5F6",  # Brighter blue  
  "Telomere shortening" = "#4FC3F7",  # Vivid sky blue  
  "DNA demethylation" = "#BA68C8",  # Rich lavender  
  "Oxidative stress" = "#FDD835",  # Strong yellow  
  "Conditioned Medium" = "#F2994A",  # Warm orange  
  "Oncogene" = "#81C784",  # Medium green  
  "Lipid Accumulation" = "#E57373",  # Coral  
  "Calcium influx" = "#26A69A",  # Deep teal  
  "Plasma membrane dysruption" = "#D32F2F",  # Strong salmon  
  "OSKM factors" = "#FFB74D",  # Bright peach  
  "YAP KO" = "#9575CD"  # Deep pastel purple  
)

cellTypes_colors <- c(
  "Fibroblast" = "#FF6961",   # Strong Pastel Red  
  "Keratinocyte" = "#FFB347", # Strong Pastel Orange  
  "Melanocyte" = "#FFD700",   # Strong Pastel Yellow  
  "Endothelial" = "#77DD77",  # Strong Pastel Green  
  "Neuronal" = "#779ECB",     # Strong Pastel Blue  
  "Mesenchymal" = "#C27BA0"   # Strong Pastel Purple  
)

cond_cohend <- list(A=c("Senescent"), # if no variable is defined, will be the first that appears in the ggplot
                    B=c("Proliferative","Quiescent"))

PlotScores(ResultsList = df_logmedian, ColorVariable = "CellType", GroupingVariable="Condition",  method ="logmedian", ColorValues = cellTypes_colors, ConnectGroups=TRUE, ncol = 6, nrow = 2, widthTitle=20, y_limits = NULL, legend_nrow = 2,xlab=NULL, cond_cohend = cond_cohend)

df_ranking <- CalculateScores(data = corrcounts_merge, metadata = metadata_merge, method = "ranking", gene_sets = SenescenceSignatures)
Considering unidirectional gene signature mode for signature [DOWN]_CellAge
Considering unidirectional gene signature mode for signature [DOWN]_HernandezSegura
Considering unidirectional gene signature mode for signature [DOWN]_SeneQuest
Considering unidirectional gene signature mode for signature [UP]_CellAge
Considering unidirectional gene signature mode for signature [UP]_HernandezSegura
Considering unidirectional gene signature mode for signature [UP]_SeneQuest
Considering unidirectional gene signature mode for signature CSgene
Considering unidirectional gene signature mode for signature GOBP_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature REACTOME_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature SAUL_SEN_MAYO
senescence_triggers_colors <- c(
  "none" = "#E57373",  # Soft red  
  "Radiation" = "#BDBDBD",  # Medium gray  
  "DNA damage" = "#64B5F6",  # Brighter blue  
  "Telomere shortening" = "#4FC3F7",  # Vivid sky blue  
  "DNA demethylation" = "#BA68C8",  # Rich lavender  
  "Oxidative stress" = "#FDD835",  # Strong yellow  
  "Conditioned Medium" = "#F2994A",  # Warm orange  
  "Oncogene" = "#81C784",  # Medium green  
  "Lipid Accumulation" = "#E57373",  # Coral  
  "Calcium influx" = "#26A69A",  # Deep teal  
  "Plasma membrane dysruption" = "#D32F2F",  # Strong salmon  
  "OSKM factors" = "#FFB74D",  # Bright peach  
  "YAP KO" = "#9575CD"  # Deep pastel purple  
)

cellTypes_colors <- c(
  "Fibroblast" = "#FF6961",   # Strong Pastel Red  
  "Keratinocyte" = "#FFB347", # Strong Pastel Orange  
  "Melanocyte" = "#FFD700",   # Strong Pastel Yellow  
  "Endothelial" = "#77DD77",  # Strong Pastel Green  
  "Neuronal" = "#779ECB",     # Strong Pastel Blue  
  "Mesenchymal" = "#C27BA0"   # Strong Pastel Purple  
)

cond_cohend <- list(A=c("Senescent"), # if no variable is defined, will be the first that appears in the ggplot
                    B=c("Proliferative","Quiescent"))

PlotScores(ResultsList = df_ranking, ColorVariable = "CellType", GroupingVariable="Condition",  method ="ranking", ColorValues = cellTypes_colors, ConnectGroups=TRUE, ncol = 6, nrow = 2, widthTitle=20, y_limits = NULL, legend_nrow = 2,xlab=NULL, cond_cohend = cond_cohend)


plotlist <- list()

for (sig in names(df_ssGSEA)){
  
  df_subset_ssGSEA <- df_ssGSEA[[sig]]
  df_subset_logmedian <- df_logmedian[[sig]]
  
  df_subset_merge <- merge(df_subset_ssGSEA,df_subset_logmedian,by="sample")
  
  # Wrap the signature name using the helper function
  wrapped_title <- wrap_title_aux(sig, width = 20)  
  
  plotlist[[sig]] <- ggplot2::ggplot(df_subset_merge, aes(x=score.x, y=score.y)) +
    geom_point(size=4, alpha=0.8, fill="darkgrey", shape=21) +
    theme_bw() +
    xlab("ssGSEA Enrichment Score") +
    ylab("Normalised Signature Score") +
    ggtitle(wrapped_title) +
    theme(plot.title = ggplot2::element_text(hjust = 0.5, size=10),
          plot.subtitle = ggplot2::element_text(hjust = 0.5)) 
  
}

ggpubr::ggarrange(plotlist=plotlist, nrow=3, ncol=4, align = "h")

Bidirectional gene signatures

Try scores with bidirectional signatures

bidirectsigs <- readRDS("~/VersionControl/senescence_benchmarking/CommonFiles/SenescenceSignatures_complete_newCellAge.RDS")
for (sig in names(bidirectsigs)){
  sigdf <- bidirectsigs[[sig]]
  sigdf <- sigdf[,1:2] # remove the third column, if applicable
  if(any(sigdf[,2]=="not_reported")){
    sigdf <- sigdf[,1]
    bidirectsigs[[sig]] <- sigdf
    next 
  }
  sigdf[,2] <- ifelse(sigdf[,2]=="enriched",1,-1)
  bidirectsigs[[sig]] <- sigdf
}
bidirectsigs
$CellAge

$CSgene
  [1] "TP53"       "TERF2"      "MAPK14"     "CDKN2A"     "CDKN1A"     "CCNE1"      "CCNA1"      "MAPKAPK5"   "CBX4"       "TXN"        "TBX2"      
 [12] "STAT3"      "SRF"        "BMI1"       "MAP2K4"     "MAP2K6"     "MAP2K3"     "MAPK8"      "MAPK3"      "MAPK1"      "PRKCD"      "PML"       
 [23] "OPA1"       "ATM"        "MDM2"       "CXCL8"      "IL6"        "IGFBP7"     "ID1"        "HRAS"       "H2AFX"      "POT1"       "SIRT1"     
 [34] "KDM6B"      "PLA2R1"     "EZH2"       "E2F3"       "E2F1"       "CEBPB"      "CDKN2D"     "CDKN2B"     "CDKN1B"     "CDK6"       "CDK4"      
 [45] "CDK2"       "CDC42"      "RBX1"       "CDC27"      "CDK1"       "MAML1"      "CD44"       "MAD2L1BP"   "MAP4K4"     "AIM2"       "RECQL4"    
 [56] "ARHGAP18"   "KL"         "MAPKAPK2"   "AURKB"      "SLC16A7"    "CCNE2"      "HIST1H2BJ"  "HIST1H3F"   "CCNA2"      "MCM3AP"     "CDC16"     
 [67] "TSC22D1"    "CBS"        "TNFSF13"    "CTNNAL1"    "EED"        "PNPT1"      "CDC23"      "RNASET2"    "TP63"       "CAV1"       "MKNK1"     
 [78] "TSLP"       "HIST1H2BK"  "PPM1D"      "HAVCR2"     "CBX2"       "KDM2B"      "DPY30"      "C2orf40"    "YPEL3"      "HIST2H4A"   "HIST1H4L"  
 [89] "HIST1H4E"   "HIST1H4B"   "HIST1H4H"   "HIST1H4C"   "HIST1H4J"   "HIST1H4K"   "HIST1H4F"   "HIST1H4D"   "HIST1H4A"   "HIST1H3B"   "HIST1H3H"  
[100] "HIST1H3J"   "HIST1H3G"   "HIST1H3I"   "HIST1H3E"   "HIST1H3C"   "HIST1H3D"   "HIST1H3A"   "HIST2H2BE"  "HIST1H2BO"  "HIST1H2BC"  "HIST1H2BI" 
[111] "HIST1H2BH"  "HIST1H2BE"  "HIST1H2BF"  "HIST1H2BM"  "HIST1H2BN"  "HIST1H2BL"  "HIST1H2BG"  "HIST2H2AC"  "HIST2H2AA3" "HIST1H2AB"  "HIST1H2AC" 
[122] "HIST1H2AJ"  "HIST1H4I"   "HIST3H3"    "CALR"       "HMGA2"      "PHC3"       "KAT6A"      "EHMT1"      "SMC6"       "AIMP2"      "CALCA"     
[133] "DEK"        "MAPKAPK3"   "ZNF148"     "YY1"        "WRN"        "WNT5A"      "NR1H2"      "UBE3A"      "UBE2E1"     "UBE2D1"     "UBC"       
[144] "UBB"        "UBA52"      "CDC26P1"    "TYMS"       "TWIST1"     "HIRA"       "RPS27AP11"  "HIST2H2AA4" "TP73"       "TOP 1,00"   "TNF"       
[155] "TGFB2"      "TGFB1"      "TFDP1"      "TERT"       "TERF1"      "BUB1B"      "BUB1"       "TCF3"       "TBX3"       "TAGLN"      "STAT6"     
[166] "STAT1"      "BRAF"       "SREBF1"     "BRCA1"      "SP1"        "SOX5"       "SOD2"       "SNAI1"      "SMARCB1"    "SMARCA2"    "HIST2H3D"  
[177] "PHC1P1"     "ACD"        "SKIL"       "LOC649620"  "SLC13A3"    "LOC647654"  "SMURF2"     "ANAPC1"     "SHC1"       "CPEB1"      "H3F3AP6"   
[188] "ZMAT3"      "RBBP4P1"    "SRSF3"      "SRSF1"      "SATB1"      "S100A6"     "RXRB"       "RRM2"       "RRM1"       "RPS27A"     "RPS6KA3"   
[199] "RPS6KA2"    "RPS6KA1"    "RPL5"       "RNF2"       "RIT1"       "RING1"      "BCL2L1"     "RELA"       "BCL2"       "CCND1"      "RBP2"      
[210] "RBL2"       "RBL1"       "RBBP7"      "RBBP4"      "NTN4"       "RB1"        "IL21"       "RAN"        "RAF1"       "RAC1"       "TNRC6C"    
[221] "KIAA1524"   "EP400"      "CNOT6"      "CBX8"       "PTEN"       "SEPN1"      "BACH1"      "PSMB5"      "PROX1"      "PRL"        "MAP2K7"    
[232] "MAP2K1"     "MAPK10"     "MAPK9"      "MAPK11"     "MAPK7"      "PRKDC"      "RNF114"     "PRKCI"      "ATF7IP"     "MFN1"       "PRKAA2"    
[243] "CDKN2AIP"   "RBM38"      "PRG2"       "HIST2H4B"   "HJURP"      "TMEM140"    "PBRM1"      "Mar-05"     "PPARG"      "PPARD"      "POU2F1"    
[254] "TERF2IP"    "ERRFI1"     "H2BFS"      "PLK1"       "PLAUR"      "PIN1"       "PIM1"       "PIK3CA"     "PHB"        "PGR"        "PGD"       
[265] "PIAS4"      "PDGFB"      "SIRT6"      "ANAPC11"    "ANAPC7"     "ANAPC5"     "WNT16"      "FZR1"       "ZBTB7A"     "ERGIC2"     "PCNA"      
[276] "FIS1"       "PAX3"       "NOX4"       "MINK1"      "PEBP1"      "YBX1"       "NINJ1"      "NFKB1"      "H2AFB1"     "NDN"        "NCAM1"     
[287] "NBN"        "MYC"        "MYBL2"      "MSN"        "ASS1"       "LOC441488"  "MRE11A"     "MOV10"      "MMP7"       "MIF"        "MAP3K5"    
[298] "MAP3K1"     "MECP2"      "MCL1"       "MAGEA2"     "SMAD9"      "SMAD7"      "SMAD6"      "SMAD5"      "SMAD4"      "SMAD3"      "SMAD2"     
[309] "SMAD1"      "MAD2L1"     "MXD1"       "MIR34A"     "MIR30A"     "MIR299"     "MIR29A"     "MIR22"      "MIR217"     "MIR21"      "MIR205"    
[320] "MIR203A"    "MIR191"     "MIR146A"    "MIR141"     "MIR10B"     "ARNTL"      "LMNB1"      "LMNA"       "LGALS9"     "RHOA"       "KRT5"      
[331] "KRAS"       "KIT"        "KIR2DL4"    "KCNJ12"     "JUN"        "JAK2"       "ITGB4"      "IRS1"       "IRF7"       "IRF5"       "IRF3"      
[342] "ING1"       "IDO1"       "ILF3"       "IL15"       "IL12B"      "CXCR2"      "IL4"        "IGFBP5"     "IGFBP3"     "IGFBP1"     "IGF1R"     
[353] "IGF1"       "H3F3AP5"    "IFNG"       "IFI16"      "IDH1"       "ID2"        "HIST2H3A"   "BIRC5"      "HSPB1"      "HSPA9"      "HSPA5"     
[364] "HSPA1A"     "APEX1"      "HNRNPA1"    "FOXA3"      "FOXA2"      "FOXA1"      "HMGA1"      "HIF1A"      "ANXA5"      "HELLS"      "HDAC1"     
[375] "H3F3B"      "H3F3A"      "HIST1H2BB"  "HIST1H2BD"  "H2AFZ"      "HIST1H2AD"  "HIST1H2AE"  "ANAPC4"     "ANAPC2"     "UBN1"       "SENP1"     
[386] "GUCY2C"     "GSK3B"      "UHRF1"      "BRD7"       "NSMCE2"     "PTRF"       "GPI"        "GNAO1"      "RPS6KA6"    "TNRC6A"     "AGO2"      
[397] "B3GAT1"     "DNAJC2"     "GJA1"       "AGO1"       "EHF"        "TINF2"      "LDLRAP1"    "ULK3"       "GAPDH"      "ABI3BP"     "ASF1A"     
[408] "HIST1H2BA"  "G6PD"       "ACKR1"      "MTOR"       "CDC26"      "CNOT6L"     "FOS"        "CABIN1"     "MORC3"      "SUZ12"      "NPTXR"     
[419] "CBX6"       "SIRT3"      "CRTC1"      "PPP1R13B"   "SUN1"       "SMC5"       "TNRC6B"     "FOXO1"      "FOXM1"      "TNIK"       "SCMH1"     
[430] "DKK 1,00"   "FGFR2"      "FGF2"       "HEPACAM"    "FANCD2"     "EWSR1"      "ETS2"       "ETS1"       "ESR2"       "ERF"        "AKT1"      
[441] "EREG"       "ERBB2"      "ENG"        "ELN"        "CRTC2"      "EIF5A"      "EGR1"       "EGFR"       "EEF1B2"     "AGO4"       "AGO3"      
[452] "EEF1A1"     "PHC2"       "PHC1"       "ABCA1"      "E2F2"       "DUSP6"      "DUSP4"      "HBEGF"      "AGT"        "DNMT3A"     "AGER"      
[463] "DKC1"       "DAXX"       "CYP3A4"     "CTSZ"       "CTSD"       "CSNK2A1"    "E2F7"       "PARP1"      "HIST3H2BB"  "HIST2H3C"   "JDP2"      
[474] "HIST4H4"    "CLU"        "CKB"        "RASSF1"     "CHEK1"      "TOPBP1"     "UBE2C"      "KIF2C"      "BTG3"       "EHMT2"      "GADD45G"   
[485] "NEK6"       "ZMYND11"    "SPINT2"     "CENPA"      "AGR2"       "CEBPG"      "HYOU1"      "TADA3"      "MCRS1"      "NDRG1"      "ANAPC10"   
[496] "CDKN2C"     "ZMPSTE24"   "PSMD14"     "NAMPT"      "RAD50"      "TRIM10"     "DNM1L"      "BCL2L11"   

$GOBP_CELLULAR_SENESCENCE
  [1] "AKT3"     "MIR543"   "CDK2"     "CDK6"     "CDKN1A"   "ZMPSTE24" "CDKN1B"   "CDKN2A"   "CDKN2B"   "CITED2"   "KAT5"     "PLK2"     "NEK6"     "ZNF277"  
 [15] "CGAS"     "COMP"     "MAPK14"   "VASH1"    "PLA2R1"   "SMC5"     "SIRT1"    "MORC3"    "NUP62"    "ABL1"     "ULK3"     "RSL1D1"   "FBXO5"    "FBXO4"   
 [29] "MAGEA2B"  "NSMCE2"   "H2AX"     "HLA-G"    "HMGA1"    "HRAS"     "ID2"      "IGF1R"    "ING2"     "KIR2DL4"  "ARG2"     "LMNA"     "BMAL1"    "MIR10A"  
 [43] "MIR146A"  "MIR17"    "MIR188"   "MIR217"   "MIR22"    "MIR34A"   "MAGEA2"   "MAP3K3"   "MAP3K5"   "MIF"      "MNT"      "ATM"      "NPM1"     "YBX1"    
 [57] "OPA1"     "PAWR"     "ABI3"     "FZR1"     "WNT16"    "SIRT6"    "PML"      "PRMT6"    "PRELP"    "PRKCD"    "MAPK8"    "MAPK11"   "MAPK9"    "MAPK10"  
 [71] "MAP2K1"   "MAP2K3"   "MAP2K6"   "MAP2K7"   "B2M"      "ZMIZ1"    "PTEN"     "MIR20B"   "RBL1"     "BCL6"     "MAP2K4"   "BMPR1A"   "SPI1"     "SRF"     
 [85] "BRCA2"    "NEK4"     "TBX2"     "TBX3"     "MIR590"   "TERC"     "TERF2"    "TERT"     "TOP2B"    "TP53"     "TWIST1"   "WNT1"     "WRN"      "SMC6"    
 [99] "KAT6A"    "ZKSCAN3"  "HMGA2"    "CALR"     "YPEL3"    "ECRG4"    "MAPKAPK5" "TP63"     "PNPT1"    "DNAJA3"   "EEF1E1"   "NUAK1"   

$GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE

$GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE

$HernandezSegura

$REACTOME_CELLULAR_SENESCENCE
  [1] "CDC27"    "E2F2"     "SCMH1"    "MRE11"    "MAP2K3"   "MAPK9"    "ANAPC4"   "MAP2K4"   "MAP4K4"   "RPS6KA2"  "UBE2D1"   "EED"      "MAP2K7"   "TNRC6C"  
 [15] "MAPKAPK5" "ANAPC5"   "TNRC6A"   "TINF2"    "AGO1"     "CDC23"    "CABIN1"   "MAPK1"    "HIRA"     "TNRC6B"   "E2F1"     "RBBP7"    "MAPK3"    "ACD"     
 [29] "NBN"      "CCNE1"    "FZR1"     "ERF"      "CDK6"     "H2AZ2"    "EZH2"     "MAPK8"    "UBE2S"    "MAP2K6"   "NFKB1"    "MAPK10"   "ANAPC15"  "CDKN1B"  
 [43] "PHC1"     "ASF1A"    "MAPK14"   "E2F3"     "LMNB1"    "RAD50"    "TFDP2"    "MAPKAPK3" "IL1A"     "RPS6KA1"  "UBN1"     "RNF2"     "CDKN2C"   "CDK2"    
 [57] "H1-3"     "H1-1"     "H2BC11"   "CDKN1A"   "ID1"      "AGO3"     "POT1"     "CDKN2D"   "CDC16"    "H3-3B"    "KDM6B"    "TERF2"    "CCNA1"    "PHC2"    
 [71] "AGO4"     "ETS1"     "CDK4"     "MDM2"     "IL6"      "TXN"      "HMGA1"    "RB1"      "MINK1"    "TP53"     "ANAPC11"  "CBX8"     "CBX4"     "RPS27A"  
 [85] "CCNA2"    "H2BC1"    "TERF1"    "CDKN2B"   "CDKN2A"   "ATM"      "HMGA2"    "UBC"      "VENTX"    "ANAPC1"   "TNIK"     "MOV10"    "ETS2"     "H2BC5"   
 [99] "H4C8"     "RBBP4"    "MAPKAPK2" "H3-3A"    "IGFBP7"   "ANAPC10"  "ANAPC16"  "MAPK7"    "TERF2IP"  "H3-4"     "BMI1"     "H1-4"     "STAT3"    "CXCL8"   
[113] "UBE2E1"   "UBB"      "FOS"      "IFNB1"    "CEBPB"    "KAT5"     "RELA"     "PHC3"     "CBX2"     "UBE2C"    "CCNE2"    "ANAPC2"   "CDC26"    "RPS6KA3" 
[127] "JUN"      "SUZ12"    "H2AC6"    "H2BC4"    "EHMT1"    "EP400"    "H3C13"    "CBX6"     "H2AC20"   "H1-5"     "H2BC21"   "H2BC13"   "MAPK11"   "SP1"     
[141] "H1-2"     "H2AX"     "H1-0"     "ANAPC7"   "H2AC7"    "H2BC26"   "H4C3"     "H3C12"    "H4C11"    "H3C4"     "MAP3K5"   "H4C16"    "H2BC12"   "TFDP1"   
[155] "MDM4"     "H3C14"    "H3C15"    "RING1"    "EHMT2"    "UBA52"    "H2AJ"     "H4C15"    "H4C14"    "H4C12"    "H2BC14"   "H2BC8"    "H3C8"     "H2AB1"   
[169] "H2BC6"    "H4C6"     "H2BC17"   "H3C6"     "H4C13"    "H3C11"    "H2BC9"    "H3C1"     "H4C9"     "H2AC14"   "H2BC3"    "H4C5"     "H2AC8"    "H4C4"    
[183] "H2BC7"    "H3C7"     "H2AC4"    "H2BC10"   "H4C1"     "H4C2"     "H3C10"    "MIR24-2"  "MIR24-1"  "H3C2"     "H3C3"     "H2AC18"   "H2AC19"  

$SAUL_SEN_MAYO

$SeneQuest
NA
df_logmedian <- CalculateScores(data = corrcounts_merge, metadata = metadata_merge, method = "logmedian", gene_sets = bidirectsigs)
Considering bidirectional gene signature mode for signature CellAge
Considering unidirectional gene signature mode for signature CSgene
Considering unidirectional gene signature mode for signature GOBP_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering bidirectional gene signature mode for signature HernandezSegura
Considering unidirectional gene signature mode for signature REACTOME_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature SAUL_SEN_MAYO
Considering bidirectional gene signature mode for signature SeneQuest
senescence_triggers_colors <- c(
  "none" = "#E57373",  # Soft red  
  "Radiation" = "#BDBDBD",  # Medium gray  
  "DNA damage" = "#64B5F6",  # Brighter blue  
  "Telomere shortening" = "#4FC3F7",  # Vivid sky blue  
  "DNA demethylation" = "#BA68C8",  # Rich lavender  
  "Oxidative stress" = "#FDD835",  # Strong yellow  
  "Conditioned Medium" = "#F2994A",  # Warm orange  
  "Oncogene" = "#81C784",  # Medium green  
  "Lipid Accumulation" = "#E57373",  # Coral  
  "Calcium influx" = "#26A69A",  # Deep teal  
  "Plasma membrane dysruption" = "#D32F2F",  # Strong salmon  
  "OSKM factors" = "#FFB74D",  # Bright peach  
  "YAP KO" = "#9575CD"  # Deep pastel purple  
)

cellTypes_colors <- c(
  "Fibroblast" = "#FF6961",   # Strong Pastel Red  
  "Keratinocyte" = "#FFB347", # Strong Pastel Orange  
  "Melanocyte" = "#FFD700",   # Strong Pastel Yellow  
  "Endothelial" = "#77DD77",  # Strong Pastel Green  
  "Neuronal" = "#779ECB",     # Strong Pastel Blue  
  "Mesenchymal" = "#C27BA0"   # Strong Pastel Purple  
)

cond_cohend <- list(A=c("Senescent"), # if no variable is defined, will be the first that appears in the ggplot
                    B=c("Proliferative","Quiescent"))

PlotScores(ResultsList = df_logmedian, ColorVariable = "CellType", GroupingVariable="Condition",  method ="logmedian", ColorValues = cellTypes_colors, ConnectGroups=TRUE, ncol = 3, nrow = 3, widthTitle=20, y_limits = NULL, legend_nrow = 2,xlab=NULL, cond_cohend = cond_cohend)

 
df_ssgsea <- CalculateScores(data = corrcounts_merge, metadata = metadata_merge, method = "ssGSEA", gene_sets = bidirectsigs)
Considering bidirectional gene signature mode for signature CellAge
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature CSgene
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering bidirectional gene signature mode for signature HernandezSegura
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature REACTOME_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature SAUL_SEN_MAYO
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering bidirectional gene signature mode for signature SeneQuest
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
senescence_triggers_colors <- c(
  "none" = "#E57373",  # Soft red  
  "Radiation" = "#BDBDBD",  # Medium gray  
  "DNA damage" = "#64B5F6",  # Brighter blue  
  "Telomere shortening" = "#4FC3F7",  # Vivid sky blue  
  "DNA demethylation" = "#BA68C8",  # Rich lavender  
  "Oxidative stress" = "#FDD835",  # Strong yellow  
  "Conditioned Medium" = "#F2994A",  # Warm orange  
  "Oncogene" = "#81C784",  # Medium green  
  "Lipid Accumulation" = "#E57373",  # Coral  
  "Calcium influx" = "#26A69A",  # Deep teal  
  "Plasma membrane dysruption" = "#D32F2F",  # Strong salmon  
  "OSKM factors" = "#FFB74D",  # Bright peach  
  "YAP KO" = "#9575CD"  # Deep pastel purple  
)

cellTypes_colors <- c(
  "Fibroblast" = "#FF6961",   # Strong Pastel Red  
  "Keratinocyte" = "#FFB347", # Strong Pastel Orange  
  "Melanocyte" = "#FFD700",   # Strong Pastel Yellow  
  "Endothelial" = "#77DD77",  # Strong Pastel Green  
  "Neuronal" = "#779ECB",     # Strong Pastel Blue  
  "Mesenchymal" = "#C27BA0"   # Strong Pastel Purple  
)

cond_cohend <- list(A=c("Senescent"), # if no variable is defined, will be the first that appears in the ggplot
                    B=c("Proliferative","Quiescent"))

PlotScores(ResultsList = df_ssgsea, ColorVariable = "CellType", GroupingVariable="Condition",  method ="ssGSEA", ColorValues = cellTypes_colors, ConnectGroups=TRUE, ncol = 3, nrow = 3, widthTitle=20, y_limits = NULL, legend_nrow = 2,xlab=NULL, cond_cohend = cond_cohend)

 
df_ranking <- CalculateScores(data = corrcounts_merge, metadata = metadata_merge, method = "ranking", gene_sets = bidirectsigs)
Considering bidirectional gene signature mode for signature CellAge
Considering unidirectional gene signature mode for signature CSgene
Considering unidirectional gene signature mode for signature GOBP_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering bidirectional gene signature mode for signature HernandezSegura
Considering unidirectional gene signature mode for signature REACTOME_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature SAUL_SEN_MAYO
Considering bidirectional gene signature mode for signature SeneQuest
senescence_triggers_colors <- c(
  "none" = "#E57373",  # Soft red  
  "Radiation" = "#BDBDBD",  # Medium gray  
  "DNA damage" = "#64B5F6",  # Brighter blue  
  "Telomere shortening" = "#4FC3F7",  # Vivid sky blue  
  "DNA demethylation" = "#BA68C8",  # Rich lavender  
  "Oxidative stress" = "#FDD835",  # Strong yellow  
  "Conditioned Medium" = "#F2994A",  # Warm orange  
  "Oncogene" = "#81C784",  # Medium green  
  "Lipid Accumulation" = "#E57373",  # Coral  
  "Calcium influx" = "#26A69A",  # Deep teal  
  "Plasma membrane dysruption" = "#D32F2F",  # Strong salmon  
  "OSKM factors" = "#FFB74D",  # Bright peach  
  "YAP KO" = "#9575CD"  # Deep pastel purple  
)

cellTypes_colors <- c(
  "Fibroblast" = "#FF6961",   # Strong Pastel Red  
  "Keratinocyte" = "#FFB347", # Strong Pastel Orange  
  "Melanocyte" = "#FFD700",   # Strong Pastel Yellow  
  "Endothelial" = "#77DD77",  # Strong Pastel Green  
  "Neuronal" = "#779ECB",     # Strong Pastel Blue  
  "Mesenchymal" = "#C27BA0"   # Strong Pastel Purple  
)

cond_cohend <- list(A=c("Senescent"), # if no variable is defined, will be the first that appears in the ggplot
                    B=c("Proliferative","Quiescent"))

PlotScores(ResultsList = df_ranking, ColorVariable = "CellType", GroupingVariable="Condition",  method ="ranking", ColorValues = cellTypes_colors, ConnectGroups=TRUE, ncol = 3, nrow = 3, widthTitle=20, y_limits = NULL, legend_nrow = 2,xlab=NULL, cond_cohend = cond_cohend)

Heatmap for Cohen’s D

 
PlotScores(data = corrcounts_merge, 
           metadata = metadata_merge,  
           gene_sets=bidirectsigs, 
           GroupingVariable="Condition",  
           method ="all",   
           ncol = NULL, 
           nrow = NULL, 
           widthTitle=30, 
           limits = NULL,   
           title="Marthandan et al. 2016", 
           titlesize = 12,
           ColorValues = NULL)  
Considering bidirectional gene signature mode for signature CellAge
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature CSgene
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering bidirectional gene signature mode for signature HernandezSegura
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature REACTOME_CELLULAR_SENESCENCE
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering unidirectional gene signature mode for signature SAUL_SEN_MAYO
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering bidirectional gene signature mode for signature SeneQuest
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE or useNames = FALSE.
No id variables; using all as measure variables
Considering bidirectional gene signature mode for signature CellAge
Considering unidirectional gene signature mode for signature CSgene
Considering unidirectional gene signature mode for signature GOBP_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering bidirectional gene signature mode for signature HernandezSegura
Considering unidirectional gene signature mode for signature REACTOME_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature SAUL_SEN_MAYO
Considering bidirectional gene signature mode for signature SeneQuest
Considering bidirectional gene signature mode for signature CellAge
Considering unidirectional gene signature mode for signature CSgene
Considering unidirectional gene signature mode for signature GOBP_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_NEGATIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature GOBP_POSITIVE_REGULATION_OF_CELLULAR_SENESCENCE
Considering bidirectional gene signature mode for signature HernandezSegura
Considering unidirectional gene signature mode for signature REACTOME_CELLULAR_SENESCENCE
Considering unidirectional gene signature mode for signature SAUL_SEN_MAYO
Considering bidirectional gene signature mode for signature SeneQuest

# missing: 
# - combine legends
# - wrap title
# - tilt x labels to 60 degrees
# - change default colors
# wrap x labels with wrap_title
# grid with common legends https://support.bioconductor.org/p/87318/

Correlation plots

If the user is investigating if a certain variable can be described from the score, and not already knowing that variable. More exploratory…

  • Define what each variable is: Numeric (includes integer if unique > 5), Categorical Bin (integer/string if unique == 2, logical), Categorical Multi (integer if unique < 5, string if unique > 2)
  • Define functions to calculate metrics based on different data types:
    • Categorical Bin: t-test/wilcoxon
    • Categorical Multi: ANOVA / Kruskal-Wallis + Tukey’s test
    • Numeric : Pearson / Spearman / Kendall’s Tau
  • Return a list:
    • One entry per variable
      • Method used
      • Data frame
        • Two columns: metric and p-value
        • One line per subvariable (if Numeric and Categorical Bin, only one line; for Categorical Multi, one per combination of variables); named rows
  • Plot results
    • If Numeric, scatter plot; metric on the top left corner
    • If Categorical, density plot, colored by the unique values of the variable; metrics (if one, or combinations of variables) in top left corner
    • Arrange in grid
options(error=recover)
plot_stat_tests(metadata_corr, target_var="score", cols = c("Condition","Is_Senescent","random_cat","random_numeric"),
                 discrete_colors = list(Is_Senescent=c("Senescent"="pink",
                                                 "Non Senescent"="orange")), 
                continuous_color = "#8C6D03", 
                            color_palette = "Set2", nrow=1, sizeannot=3, legend.position="top")
`geom_smooth()` using formula = 'y ~ x'

Individual Genes

Violin Expression Plots



senescence_triggers_colors <- c(
  "none" = "#E57373",  # Soft red  
  "Radiation" = "#BDBDBD",  # Medium gray  
  "DNA damage" = "#64B5F6",  # Brighter blue  
  "Telomere shortening" = "#4FC3F7",  # Vivid sky blue  
  "DNA demethylation" = "#BA68C8",  # Rich lavender  
  "Oxidative stress" = "#FDD835",  # Strong yellow  
  "Conditioned Medium" = "#F2994A",  # Warm orange  
  "Oncogene" = "#81C784",  # Medium green  
  "Lipid Accumulation" = "#E57373",  # Coral  
  "Calcium influx" = "#26A69A",  # Deep teal  
  "Plasma membrane dysruption" = "#D32F2F",  # Strong salmon  
  "OSKM factors" = "#FFB74D",  # Bright peach  
  "YAP KO" = "#9575CD"  # Deep pastel purple  
)


IndividualGenes_Violins(data = corrcounts_merge, metadata = metadata_merge, genes = c("CDKN1A", "CDKN2A", "GLB1","TP53","CCL2"), GroupingVariable = "Condition", plot=T, ncol=NULL, nrow=2, divide="CellType", invert_divide=FALSE,ColorValues=senescence_triggers_colors, pointSize=2, ColorVariable="SenescentType", title="Senescence", widthTitle=16,y_limits = NULL,legend_nrow=4, xlab="Condition",colorlab="") 

Correlation Heatmap

options(error=recover)
CorrelationHeatmap(data=corrcounts_merge, 
                   metadata = metadata_merge, 
                   genes=c("CDKN1A", "CDKN2A", "GLB1","TP53","CCL2"), 
                   separate.by = "Condition", 
                   method = "pearson",  
                   colorlist = list(low = "#3F4193", mid = "#F9F4AE", high = "#B44141"),
                   limits_colorscale = c(-1,0,1), 
                   widthTitle = 16, 
                   title = "test", 
                   cluster_rows = TRUE, 
                   cluster_columns = TRUE,  
                   detailedresults = FALSE, 
                   legend_position="right",
                   titlesize=20)

Expression Heatmaps

options(error=recover)

annotation_colors <- list(
  CellType = c(
    "Fibroblast"   = "#FF6961",   # Strong Pastel Red  
    "Keratinocyte" = "#FFB347",   # Strong Pastel Orange  
    "Melanocyte"   = "#FFD700",   # Strong Pastel Yellow  
    "Endothelial"  = "#77DD77",   # Strong Pastel Green  
    "Neuronal"     = "#779ECB",   # Strong Pastel Blue  
    "Mesenchymal"  = "#C27BA0"    # Strong Pastel Purple  
  ),
  Condition = c(
    "Senescent"     = "#65AC7C",  # Example color: greenish
    "Proliferative" = "#5F90D4",  # Example color: blueish
    "Quiescent"     = "#EDA03E"   # Example color: orange
  )
)

ExpressionHeatmap(data=corrcounts_merge, 
                  metadata = metadata_merge, 
                  genes=c("CDKN1A", "CDKN2A", "GLB1","TP53","CCL2"),  
                  annotate.by = c("CellType","Condition"),
                  annotation_colors = annotation_colors,
                  colorlist = list(low = "#3F4193", mid = "#F9F4AE", high = "#B44141"),
                  cluster_rows = TRUE, 
                  cluster_columns = FALSE,
                  title = "test", 
                  titlesize = 20,
                  legend_position = "right",
                  scale_position="right")

ROC/AUC


cellTypes_colors <- c(
  "Fibroblast" = "#FF6961",   # Strong Pastel Red  
  "Keratinocyte" = "#FFB347", # Strong Pastel Orange  
  "Melanocyte" = "#FFD700",   # Strong Pastel Yellow  
  "Endothelial" = "#77DD77",  # Strong Pastel Green  
  "Neuronal" = "#779ECB",     # Strong Pastel Blue  
  "Mesenchymal" = "#C27BA0"   # Strong Pastel Purple  
)

ROCandAUCplot(corrcounts_merge, 
              metadata_merge, 
              condition_var = "Condition", 
              class = "Senescent", 
              genes=c("CDKN1A", "CDKN2A", "GLB1","TP53","CCL2"), 
              group_var="CellType",
              plot_type = "all",
              heatmap_params = list(col = list( "#F9F4AE" ,"#B44141"),
                                    limits = c(0.5,1),
                                    cluster_rows=T),
              roc_params = list(nrow=2,
                                ncol=2,
                                colors=cellTypes_colors),
              commomplot_params = list(widths=c(0.5,0.5)))

Cohen’s d

CohenDHeatmap(corrcounts_merge, 
              metadata_merge, 
              genes=c("CDKN1A", "CDKN2A", "GLB1","TP53","CCL2"),
              condition_var = "Condition", 
              class = "Senescent", 
              group_var = "CellType",
              title = NULL,
              widthTitle = 16,
              heatmap_params = list(col = list( "#F9F4AE" ,"#B44141"),
                                    limits = NULL,
                                    cluster_rows=T))

PCA with genes from signature only


CellTypecols = c(
  "Fibroblast"   = "#FF6961",   # Strong Pastel Red  
  "Keratinocyte" = "#FFB347",   # Strong Pastel Orange  
  "Melanocyte"   = "#FFD700",   # Strong Pastel Yellow  
  "Endothelial"  = "#77DD77",   # Strong Pastel Green  
  "Neuronal"     = "#779ECB",   # Strong Pastel Blue  
  "Mesenchymal"  = "#C27BA0"    # Strong Pastel Purple  
)

sencols <- c(
  "Senescent" = "#D32F2F",  # Strong salmon  
  "Quiescent" = "#FFB74D",  # Bright peach  
  "Proliferative" = "#9575CD"  # Deep pastel purple  
)

plotPCA(data=corrcounts_merge, 
        metadata=metadata_merge, 
        genes=c("CDKN1A", "CDKN2A", "GLB1","TP53","CCL2"), 
        scale=FALSE, 
        center=TRUE, 
        PCs=list(c(1,2), c(2,3), c(3,4)), 
        ColorVariable="Condition",
        ColorValues=sencols,
        pointSize=5,
        legend_nrow=1, 
        ncol=3, 
        nrow=NULL)

Enrichment-based

GSEA

options(error=recover)
degenes <- calculateDE(data=corrcounts_merge, 
                       metadata=metadata_merge, 
                       variables="Condition", 
                       lmexpression = NULL, 
                       modelmat = NULL, 
                       contrasts = c("Senescent - Proliferative",
                                     "Senescent - Quiescent",
                                     "Proliferative - Quiescent")) 

degenes
$`Senescent - Proliferative`

$`Senescent - Quiescent`

$`Proliferative - Quiescent`
NA
options(error=recover)
plotVolcano(DEResultsList=degenes, genes=bidirectsigs, N=NULL, x="logFC",y="-log10(adj.P.Val)", pointSize=2, color="pink", highlightcolor="darkblue", highlightcolor_upreg = "#038C65", highlightcolor_downreg = "#8C0303", nointerestcolor="grey",threshold_y=NULL, threshold_x=NULL, xlab=NULL, ylab=NULL, ncol=NULL, nrow=NULL, title=NULL,labsize=7,widthlabs=25, invert=T)
GSEAresults <- runGSEA(degenes, bidirectsigs, stat = NULL)
GSEAresults
plotGSEAenrichment(GSEA_results=GSEAresults, DEGList=degenes, gene_sets=bidirectsigs, widthTitle=32,grid = T, titlesize = 10, nrow=3, ncol=9) 
plotNESlollipop(GSEA_results=GSEAresults, sig_threshold = 0.05,
                         low_color = "blue", mid_color = "white", high_color = "red",
                         grid = T, nrow = 1, ncol = NULL,   padj_limit=c(0,0.1), widthlabels=28, title=NULL)
 
plotCombinedGSEA(GSEAresults, sig_threshold = 0.05, PointSize=9, widthlegend = 26 )

Association with Phenotype

If the user is investigating if a certain variable can be described from the GSEA results, and not already knowing that variable. More exploratory…

  • For each variable, define all possible contrasts (e.g. if A,B,C, then consider A-B, A-C, B-C,A-(B+C)/2, etc…)

  • Use calculateDE without baseline and all possible contrasts

  • perform GSEA and collect all results in only one table

  • Plot all results in lollipop plots, y axis with all contrasts

  • One function to calculate all results; one to do the lollypop plot

# Example usage
levels <- c("A", "B" ,"C","D")
generate_all_contrasts(levels, mode="extensive")
 [1] "A - B"                 "B - A"                 "A - C"                 "C - A"                 "A - D"                 "D - A"                
 [7] "B - C"                 "C - B"                 "B - D"                 "D - B"                 "C - D"                 "D - C"                
[13] "A - ( B + C + D )/ 3"  "(  B + C + D )/ 3 - A" "B - ( A + C + D )/ 3"  "(  A + C + D )/ 3 - B" "C - ( A + B + D )/ 3"  "(  A + B + D )/ 3 - C"
[19] "D - ( A + B + C )/ 3"  "(  A + B + C )/ 3 - D" "(A + B)/2 - (C + D)/2" "(C + D)/2 - (A + B)/2" "(A + C)/2 - (B + D)/2" "(B + D)/2 - (A + C)/2"
[25] "(A + D)/2 - (B + C)/2" "(B + C)/2 - (A + D)/2"
 options(error=recover)
df_test <- GSEA_VariableAssociation(data=corrcounts_merge, 
                         metadata=metadata_merge_corr, 
                         cols=c("Condition","Is_Senescent","random_cat","random_numeric"), 
                         mode="extensive", 
                         gene_set=list(HernandezSegura=bidirectsigs$HernandezSegura), 
                         padj_limit = c(0, 0.1), low_color = "blue", mid_color = "white", high_color = "red", 
                         sig_threshold = 0.05, widthlabels=30, labsize=10, titlesize=14) 
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in fgseaMultilevel(pathways = pathways, stats = stats, minSize = minSize,  :
  There were 1 pathways for which P-values were not calculated properly due to unbalanced (positive and negative) gene-level statistic values. For such pathways pval, padj, NES, log2err are set to NA. You can try to increase the value of the argument nPermSimple (for example set it nPermSimple = 10000)
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
df_test$plot
Warning: Removed 1 row containing missing values or values outside the scale range (`geom_segment()`).
Warning: Removed 1 row containing missing values or values outside the scale range (`geom_point()`).

metadata_corr_1 <- CalculateScores(data = corrcounts_merge, metadata = metadata_merge, method = "ssGSEA", gene_sets = list(HernandezSegura=bidirectsigs$HernandezSegura) )
Considering bidirectional gene signature mode for signature HernandezSegura
No id variables; using all as measure variables
No id variables; using all as measure variables
metadata_corr <- metadata_corr_1$`HernandezSegura`
metadata_corr <- merge(metadata_corr,metadata_merge_corr[,c("sampleID","random_cat","random_numeric","Is_Senescent")], by.x="sample", by.y="sampleID",all.x = T)
metadata_corr
 
plot_stat_tests(metadata_corr, target_var="score", cols = c("Condition","Is_Senescent","random_cat","random_numeric"),
                 discrete_colors = list(Is_Senescent=c("Senescent"="pink",
                                                 "Non Senescent"="orange")), 
                continuous_color = "#8C6D03", 
                            color_palette = "Set2", nrow=4, sizeannot=3, legend.position="top")
`geom_smooth()` using formula = 'y ~ x'

degenes_test <- calculateDE(data=corrcounts_merge, 
                       metadata=metadata_merge_corr, 
                       variables="random_cat", 
                       lmexpression = NULL, 
                       modelmat = NULL, 
                       contrasts = generate_all_contrasts(c(unique(metadata_corr$random_cat)), mode = "extensive")) 

 
GSEAresults_test <- runGSEA(degenes_test, list(HernandezSegura_UP=SenescenceSignatures$`[UP]_HernandezSegura`), stat = NULL)
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.03% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
GSEAresults_test
$`C-B`

$`B-C`

$`C-A`

$`A-C`

$`B-A`

$`A-B`

$`C-(B+A)/2`

$`(B+A)/2-C`

$`B-(C+A)/2`

$`(C+A)/2-B`

$`A-(C+B)/2`

$`(C+B)/2-A`
 
options(error=recover)
plotGSEAenrichment(GSEA_results=GSEAresults_test, DEGList=degenes_test, gene_sets=list(HernandezSegura_UP=SenescenceSignatures$`[UP]_HernandezSegura`), widthTitle=32,grid = F) 
$`C-B_HernandezSegura_UP`

$`B-C_HernandezSegura_UP`

$`C-A_HernandezSegura_UP`

$`A-C_HernandezSegura_UP`

$`B-A_HernandezSegura_UP`

$`A-B_HernandezSegura_UP`

$`C-(B+A)/2_HernandezSegura_UP`

$`(B+A)/2-C_HernandezSegura_UP`

$`B-(C+A)/2_HernandezSegura_UP`

$`(C+A)/2-B_HernandezSegura_UP`

$`A-(C+B)/2_HernandezSegura_UP`

$`(C+B)/2-A_HernandezSegura_UP`

NA
 options(error=recover)
df_test <- GSEA_VariableAssociation(data=corrcounts_merge, 
                         metadata=metadata_merge_corr, 
                         cols=c("Condition" ), 
                         mode="medium", 
                         gene_set=list(HernandezSegura_UP=SenescenceSignatures$`[UP]_HernandezSegura` ), 
                         padj_limit = c(0, 0.1), low_color = "blue", mid_color = "white", high_color = "red", 
                         sig_threshold = 0.05, widthlabels=30, labsize=10, titlesize=14) 
Error in .subset2(x, i, exact = exact) : subscript out of bounds

Enter a frame number, or 0 to exit   

1: GSEA_VariableAssociation(data = corrcounts_merge, metadata = metadata_merge_corr, cols = c("Condition"), mode = "medium", gene_set = list(HernandezS
2: #40: runGSEA(DEGs_var, gene_sets = gene_set, stat = stat)
3: runGSEA.R#65: setNames(deg_df[[current_stat]], rownames(deg_df))
4: deg_df[[current_stat]]
5: `[[.data.frame`(deg_df, current_stat)
6: (function(x, i, exact) if (is.matrix(i)) as.matrix(x)[[i]] else .subset2(x, i, exact = exact))(x, ..., exact = exact)
1
Called from: setNames(deg_df[[current_stat]], rownames(deg_df))
c

Enter a frame number, or 0 to exit   

1: GSEA_VariableAssociation(data = corrcounts_merge, metadata = metadata_merge_corr, cols = c("Condition"), mode = "medium", gene_set = list(HernandezS
2: #40: runGSEA(DEGs_var, gene_sets = gene_set, stat = stat)
3: runGSEA.R#65: setNames(deg_df[[current_stat]], rownames(deg_df))
4: deg_df[[current_stat]]
5: `[[.data.frame`(deg_df, current_stat)
6: (function(x, i, exact) if (is.matrix(i)) as.matrix(x)[[i]] else .subset2(x, i, exact = exact))(x, ..., exact = exact)
2
Called from: deg_df[[current_stat]]
View(deg_df)
c

Enter a frame number, or 0 to exit   

1: GSEA_VariableAssociation(data = corrcounts_merge, metadata = metadata_merge_corr, cols = c("Condition"), mode = "medium", gene_set = list(HernandezS
2: #40: runGSEA(DEGs_var, gene_sets = gene_set, stat = stat)
3: runGSEA.R#65: setNames(deg_df[[current_stat]], rownames(deg_df))
4: deg_df[[current_stat]]
5: `[[.data.frame`(deg_df, current_stat)
6: (function(x, i, exact) if (is.matrix(i)) as.matrix(x)[[i]] else .subset2(x, i, exact = exact))(x, ..., exact = exact)
2
Called from: deg_df[[current_stat]]
setNames(deg_df[[current_stat]], rownames(deg_df))
Error during wrapup: subscript out of bounds
Error: no more error handlers available (recursive errors?); invoking 'abort' restart
current_stat
[1] "t" "B"
is.data.frame(gs)
[1] FALSE
Q

df_test$plot


df_test <- GSEA_VariableAssociation(data=corrcounts_merge, 
                         metadata=metadata_merge_corr, 
                         cols=c("Condition" ), 
                         mode="medium", 
                         gene_set=list( HernandezSegura_UP_Bidirect=subset(bidirectsigs$HernandezSegura, enrichment==1)), 
                         padj_limit = c(0, 0.1), low_color = "blue", mid_color = "white", high_color = "red", 
                         sig_threshold = 0.05, widthlabels=30, labsize=10, titlesize=14) 
Error in .subset2(x, i, exact = exact) : subscript out of bounds

Enter a frame number, or 0 to exit   

1: GSEA_VariableAssociation(data = corrcounts_merge, metadata = metadata_merge_corr, cols = c("Condition"), mode = "medium", gene_set = list(HernandezS
2: #40: runGSEA(DEGs_var, gene_sets = gene_set, stat = stat)
3: runGSEA.R#65: setNames(deg_df[[current_stat]], rownames(deg_df))
4: deg_df[[current_stat]]
5: `[[.data.frame`(deg_df, current_stat)
6: (function(x, i, exact) if (is.matrix(i)) as.matrix(x)[[i]] else .subset2(x, i, exact = exact))(x, ..., exact = exact)
#' GSEA Variable Association
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' This function assesses the association between gene expression (or another molecular score)
Enter an item from the menu, or 0 to exit
#' and metadata variables using differential expression (DE) analysis and Gene Set Enrichment Analysis (GSEA).
Enter an item from the menu, or 0 to exit
#' It generates all possible contrasts for categorical variables and uses linear modeling for continuous variables.
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' @param data A matrix or data frame containing gene expression data, where rows represent genes and columns represent samples.
Enter an item from the menu, or 0 to exit
#' @param metadata A data frame containing sample metadata with at least one column corresponding to the variables of interest.
Enter an item from the menu, or 0 to exit
#' @param cols A character vector specifying the metadata columns (variables) to analyze.
Enter an item from the menu, or 0 to exit
#' @param stat Optional. The statistic to use for ranking genes before GSEA. If `NULL`, it is automatically determined based on the gene set:
Enter an item from the menu, or 0 to exit
#'   - `"B"` for gene sets with **no known direction** (vectors).
Enter an item from the menu, or 0 to exit
#'   - `"t"` for **unidirectional** or **bidirectional** gene sets (data frames).
Enter an item from the menu, or 0 to exit
#'   - If provided, this argument overrides the automatic selection.
Enter an item from the menu, or 0 to exit
#' @param mode A character string specifying the contrast generation method for categorical variables. Options: `"simple"`, `"medium"`, `"extensive"`. Default is `"simple"`.
Enter an item from the menu, or 0 to exit
#' @param gene_set A named list defining the gene sets for GSEA. **(Required)**
Enter an item from the menu, or 0 to exit
#'   - If using **unidirectional** gene sets, provide a list where each element is a vector of gene names representing a signature.
Enter an item from the menu, or 0 to exit
#'   - If using **bidirectional** gene sets, provide a list where each element is a data frame:
Enter an item from the menu, or 0 to exit
#'    - The **first column** should contain gene names.
Enter an item from the menu, or 0 to exit
#'    - The **second column** should indicate the expected direction of enrichment (`1` for upregulated, `-1` for downregulated).
Enter an item from the menu, or 0 to exit
#' @param padj_limit A numeric vector of length 2 specifying the color scale limits for adjusted p-values in the plot. Default: `c(0, 0.1)`.
Enter an item from the menu, or 0 to exit
#' @param low_color The color representing low adjusted p-values in the plot. Default: `"blue"`.
Enter an item from the menu, or 0 to exit
#' @param mid_color The color representing the chosen value for `sig_threshold`. Default: `"white"`.
Enter an item from the menu, or 0 to exit
#' @param high_color The color representing high adjusted p-values in the plot. Default: `"red"`.
Enter an item from the menu, or 0 to exit
#' @param sig_threshold A numeric value specifying the threshold for significance visualization in the plot. Default: `0.05`.
Enter an item from the menu, or 0 to exit
#' @param widthlabels An integer controlling the maximum width of contrast labels before text wrapping. Default: `18`.
Enter an item from the menu, or 0 to exit
#' @param labsize An integer controlling the axis text size in the plot. Default: `10`.
Enter an item from the menu, or 0 to exit
#' @param titlesize An integer specifying the plot title size. Default: `14`.
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' @return A list with two elements:
Enter an item from the menu, or 0 to exit
#'   - `data`: A data frame containing the GSEA results, including normalized enrichment scores (NES), adjusted p-values, and contrasts.
Enter an item from the menu, or 0 to exit
#'   - `plot`: A ggplot2 object visualizing the GSEA results as a lollipop plot.
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' @examples
Enter an item from the menu, or 0 to exit
#' # Example usage with random data
Enter an item from the menu, or 0 to exit
#' data <- matrix(rnorm(1000), ncol = 10)
Enter an item from the menu, or 0 to exit
#' metadata <- data.frame(group = rep(c("A", "B"), each = 5))
Enter an item from the menu, or 0 to exit
#' gene_set <- list(SampleSet = c("Gene1", "Gene2", "Gene3"))
Enter an item from the menu, or 0 to exit
#' results <- GSEA_VariableAssociation(data, metadata, cols = "group", gene_set = gene_set)
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' # View results
Enter an item from the menu, or 0 to exit
#' print(results$data)
Enter an item from the menu, or 0 to exit
#' print(results$plot)
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' @export
Enter an item from the menu, or 0 to exit
GSEA_VariableAssociation <- function(data, metadata, cols, stat=NULL, mode=c("simple","medium","extensive"), gene_set, padj_limit = c(0, 0.1), low_color = "blue", mid_color = "white", high_color = "red", sig_threshold = 0.05, widthlabels=18, labsize=10, titlesize=14) {
Enter an item from the menu, or 0 to exit
  mode <- match.arg(mode)
Enter an item from the menu, or 0 to exit
  metadata <- metadata[, cols %in% colnames(metadata), drop = FALSE]
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # Identify variable types
Enter an item from the menu, or 0 to exit
  variable_types <- identify_variable_type(metadata, cols)
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # Store results and plots
Enter an item from the menu, or 0 to exit
  all_results <- list()  # Store GSEA results
Enter an item from the menu, or 0 to exit
  all_plots <- list()    # Store plots
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  cont_vec <- c()
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  for (var in cols) {
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
    # Check if the variable exists in metadata
Enter an item from the menu, or 0 to exit
    if (!(var %in% colnames(metadata))) {
Enter an item from the menu, or 0 to exit
      warning(paste0("Variable ", var, " not in metadata"))
Enter an item from the menu, or 0 to exit
      next  # Skip to the next iteration if the variable is not in metadata
Enter an item from the menu, or 0 to exit
    }
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
    # Handle based on variable type
Enter an item from the menu, or 0 to exit
    if (variable_types[var] == "Numeric") {
Enter an item from the menu, or 0 to exit
      # Use a linear model expression for continuous variables
Enter an item from the menu, or 0 to exit
      DEGs_var <- calculateDE(data = data, metadata = metadata, lmexpression = paste0("~", var))
Enter an item from the menu, or 0 to exit
      cont_vec <- c(cont_vec,c(paste0("intercept_",var),var))
Enter an item from the menu, or 0 to exit
    } else {
Enter an item from the menu, or 0 to exit
      # For categorical variables, generate contrasts
Enter an item from the menu, or 0 to exit
      uniquevalues_var <- unique(metadata[, var])
Enter an item from the menu, or 0 to exit
      uniquevalues_var <- gsub(" ", "", uniquevalues_var)
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
      contrasts <- generate_all_contrasts(uniquevalues_var, mode = mode)
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
      # Calculate differential expression results for each contrast
Enter an item from the menu, or 0 to exit
      DEGs_var <- calculateDE(data = data, metadata = metadata, variables = var, contrasts = contrasts)
Enter an item from the menu, or 0 to exit
      cont_vec <- c(cont_vec,contrasts)
Enter an item from the menu, or 0 to exit
    }
Enter an item from the menu, or 0 to exit
    set.seed("20032025")
Enter an item from the menu, or 0 to exit
    # Perform GSEA for each case
Enter an item from the menu, or 0 to exit
    GSEA_results <- runGSEA(DEGs_var, gene_sets = gene_set, stat=stat)
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
    # Collect GSEA results in a list
Enter an item from the menu, or 0 to exit
    all_results[[var]] <- GSEA_results
Enter an item from the menu, or 0 to exit
  }
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # Combine results into a data frame
Enter an item from the menu, or 0 to exit
  combined_results <- do.call(rbind, lapply(all_results, function(x) do.call(rbind, x)))
Enter an item from the menu, or 0 to exit
  combined_results$Contrast <- cont_vec
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # correct adjusted p value to correct for multiple testing for the contrasts?
Enter an item from the menu, or 0 to exit
  #combined_results$padj <- p.adjust(combined_results$padj, method = "BH")
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  combined_results_toreturn <- combined_results
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  plot_list <- list()
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # Ensure contrast ordering
Enter an item from the menu, or 0 to exit
  combined_results$Contrast <- sapply(combined_results$Contrast, function(x) wrap_title(x, widthlabels))
Enter an item from the menu, or 0 to exit
  combined_results$Contrast <- factor(combined_results$Contrast, levels = combined_results$Contrast[order(combined_results$NES)])
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  plot <- ggplot2::ggplot(combined_results, ggplot2::aes(x = NES, y = Contrast,fill = padj)) +
Enter an item from the menu, or 0 to exit
    ggplot2::geom_segment(ggplot2::aes(yend = Contrast, xend = 0), size = .5) +
Enter an item from the menu, or 0 to exit
    ggplot2::geom_point( shape = 21, stroke = 1.2, color="black", size=4) +
Enter an item from the menu, or 0 to exit
    ggplot2::scale_fill_gradient2(low = low_color, mid = mid_color, high = high_color, midpoint = sig_threshold, limits = padj_limit, na.value=high_color) +
Enter an item from the menu, or 0 to exit
    ggplot2::labs(title = unique(combined_results$pathway), x = "Normalized Enrichment Score (NES)", y = "Contrast", color = "Adj. p-value", fill = "Adj. p-value") +
Enter an item from the menu, or 0 to exit
    ggplot2::theme_minimal() +
Enter an item from the menu, or 0 to exit
    ggplot2::theme(
Enter an item from the menu, or 0 to exit
      plot.title = ggplot2::element_text(hjust = 0.5, face = "bold", size=titlesize),
Enter an item from the menu, or 0 to exit
      legend.position = "right",
Enter an item from the menu, or 0 to exit
      axis.text =  ggplot2::element_text(size=labsize)
Enter an item from the menu, or 0 to exit
    )
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  return(list(plot=plot,
Enter an item from the menu, or 0 to exit
              data=combined_results_toreturn))  # Return list if not in grid mode
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
}
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
#' Generate All Possible Contrasts Between Groups
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' This function creates statistical contrasts between levels of a categorical variable.
Enter an item from the menu, or 0 to exit
#' Users can choose the level of complexity:
Enter an item from the menu, or 0 to exit
#' - `"simple"`: Pairwise comparisons (e.g., A - B).
Enter an item from the menu, or 0 to exit
#' - `"medium"`: Pairwise comparisons plus comparisons against the mean of other groups.
Enter an item from the menu, or 0 to exit
#' - `"extensive"`: All possible groupwise contrasts, ensuring balance in the number of terms on each side.
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' @param levels A character vector of unique group levels.
Enter an item from the menu, or 0 to exit
#' @param mode A string specifying the level of detail for contrasts.
Enter an item from the menu, or 0 to exit
#' Options are `"simple"` (pairwise only), `"medium"` (pairwise + vs. mean of others), or `"extensive"` (all possible balanced groupwise contrasts). Default is `"extensive"`.
Enter an item from the menu, or 0 to exit
#'
Enter an item from the menu, or 0 to exit
#' @return A character vector of contrast expressions (without names).
Enter an item from the menu, or 0 to exit
#' @examples
Enter an item from the menu, or 0 to exit
#' levels <- c("A", "B", "C", "D")
Enter an item from the menu, or 0 to exit
#' generate_all_contrasts(levels, mode = "simple")    # Pairwise only
Enter an item from the menu, or 0 to exit
#' generate_all_contrasts(levels, mode = "medium")    # Pairwise + mean comparisons
Enter an item from the menu, or 0 to exit
#' generate_all_contrasts(levels, mode = "extensive") # All balanced contrasts
Enter an item from the menu, or 0 to exit
#' @export
Enter an item from the menu, or 0 to exit
generate_all_contrasts <- function(levels, mode = "extensive") {
Enter an item from the menu, or 0 to exit
  levels <- unique(levels)  # Ensure unique levels
Enter an item from the menu, or 0 to exit
  n <- length(levels)       # Total number of levels
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  if (!mode %in% c("simple", "medium", "extensive")) {
Enter an item from the menu, or 0 to exit
    stop("Invalid mode. Choose 'simple', 'medium', or 'extensive'.")
Enter an item from the menu, or 0 to exit
  }
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  contrasts <- c()  # Store contrasts
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # 1. Pairwise comparisons (included in all modes, both A - B and B - A)
Enter an item from the menu, or 0 to exit
  pairwise_contrasts <- combn(levels, 2, function(x) c(paste(x[1], "-", x[2]), paste(x[2], "-", x[1])), simplify = TRUE)
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  if (mode == "simple") {
Enter an item from the menu, or 0 to exit
    return(unname(as.vector(pairwise_contrasts)))
Enter an item from the menu, or 0 to exit
  }
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # 2. Comparisons against the mean of other groups (included in medium & extensive)
Enter an item from the menu, or 0 to exit
  mean_contrasts <- unlist(lapply(levels, function(x) {
Enter an item from the menu, or 0 to exit
    others <- setdiff(levels, x)
Enter an item from the menu, or 0 to exit
    if (length(others) > 1) {
Enter an item from the menu, or 0 to exit
      return(c(
Enter an item from the menu, or 0 to exit
        paste(x, "- (", paste(others, collapse = " + "), ")/", length(others)),
Enter an item from the menu, or 0 to exit
        paste("( ", paste(others, collapse = " + "), ")/", length(others), "-", x)
Enter an item from the menu, or 0 to exit
      ))
Enter an item from the menu, or 0 to exit
    } else {
Enter an item from the menu, or 0 to exit
      return(c(paste(x, "-", others), paste(others, "-", x)))  # Simple case: keep both orders
Enter an item from the menu, or 0 to exit
    }
Enter an item from the menu, or 0 to exit
  }))
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  if (mode == "medium") {
Enter an item from the menu, or 0 to exit
    return(unname(c(as.vector(pairwise_contrasts), mean_contrasts)))
Enter an item from the menu, or 0 to exit
  }
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # 3. Groupwise comparisons (only included in extensive mode)
Enter an item from the menu, or 0 to exit
  group_contrasts <- c()
Enter an item from the menu, or 0 to exit
  for (i in 1:(n-1)) {
Enter an item from the menu, or 0 to exit
    left_groups <- combn(levels, i, simplify = FALSE)  # Subsets for the first group
Enter an item from the menu, or 0 to exit
    for (left in left_groups) {
Enter an item from the menu, or 0 to exit
      right <- setdiff(levels, left)  # Remaining elements for the second group
Enter an item from the menu, or 0 to exit
      if (length(right) > 1 && length(left) > 1) {
Enter an item from the menu, or 0 to exit
        left_weighted <- paste0("(", paste(left, collapse = " + "), ")/", length(left))
Enter an item from the menu, or 0 to exit
        right_weighted <- paste0("(", paste(right, collapse = " + "), ")/", length(right))
Enter an item from the menu, or 0 to exit
        contrast1 <- paste(left_weighted, "-", right_weighted)
Enter an item from the menu, or 0 to exit
        contrast2 <- paste(right_weighted, "-", left_weighted)
Enter an item from the menu, or 0 to exit
        group_contrasts <- c(group_contrasts, contrast1, contrast2)  # Keep both orders
Enter an item from the menu, or 0 to exit
      }
Enter an item from the menu, or 0 to exit
    }
Enter an item from the menu, or 0 to exit
  }
Enter an item from the menu, or 0 to exit
Enter an item from the menu, or 0 to exit
  # Combine all contrasts and return as an unnamed vector
Enter an item from the menu, or 0 to exit
  contrasts <- unique(c(as.vector(pairwise_contrasts), mean_contrasts, group_contrasts))  # Remove duplicates
Enter an item from the menu, or 0 to exit
  return(unname(contrasts))
Enter an item from the menu, or 0 to exit
}
Enter an item from the menu, or 0 to exit
0

df_test$plot

NA
NA
LS0tCnRpdGxlOiAiRGVidWdnaW5nIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIEltcG9ydCBEYXRhCgpgYGB7cn0KY29ycmNvdW50c19tZXJnZSA8LSByZWFkUkRTKCJ+L1ZlcnNpb25Db250cm9sL3NlbmVzY2VuY2VfYmVuY2htYXJraW5nL0RhdGEvY29ycmNvdW50c19tZXJnZS5yZHMiKQptZXRhZGF0YV9tZXJnZSA8LSByZWFkUkRTKCJ+L1ZlcnNpb25Db250cm9sL3NlbmVzY2VuY2VfYmVuY2htYXJraW5nL0RhdGEvbWV0YWRhdGFfbWVyZ2UucmRzIikKU2VuZXNjZW5jZVNpZ25hdHVyZXMgPC0gcmVhZFJEUygifi9WZXJzaW9uQ29udHJvbC9zZW5lc2NlbmNlX2JlbmNobWFya2luZy9Db21tb25GaWxlcy9TZW5lc2NlbmNlU2lnbmF0dXJlc19kaXZpZGVkX25ld0NlbGxBZ2UuUkRTIikKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoIjEyMzQ1NiIpCm1ldGFkYXRhX21lcmdlX2NvcnIgPC0gbWV0YWRhdGFfbWVyZ2UKbWV0YWRhdGFfbWVyZ2VfY29yciRyYW5kb21fY2F0IDwtICBzYW1wbGUoYygiQSIsIkIiLCJDIiksIG5yb3cobWV0YWRhdGFfbWVyZ2VfY29yciksIHJlcGxhY2UgPSBUKQptZXRhZGF0YV9tZXJnZV9jb3JyJHJhbmRvbV9udW1lcmljIDwtIHNhbXBsZSgwOjEwMCwgbnJvdyhtZXRhZGF0YV9tZXJnZV9jb3JyKSwgcmVwbGFjZSA9IFRSVUUpCm1ldGFkYXRhX21lcmdlX2NvcnIkSXNfU2VuZXNjZW50IDwtIGlmZWxzZShtZXRhZGF0YV9tZXJnZV9jb3JyJENvbmRpdGlvbiA9PSAiU2VuZXNjZW50IiwgIlNlbmVzY2VudCIsICJOb24gU2VuZXNjZW50IikKCmBgYAogCgpgYGB7cn0KbGlicmFyeShtYXJrZVIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoZWRnZVIpCj9tYXJrZVIKYGBgCgojIFNjb3JlcyAKCmBgYHtyfQo/Q2FsY3VsYXRlU2NvcmVzCmBgYAoKIyMgVW5pZGlyZWN0aW9uYWwKYGBge3IgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CmRmX3NzR1NFQSA8LSBDYWxjdWxhdGVTY29yZXMoZGF0YSA9IGNvcnJjb3VudHNfbWVyZ2UsIG1ldGFkYXRhID0gbWV0YWRhdGFfbWVyZ2UsIG1ldGhvZCA9ICJzc0dTRUEiLCBnZW5lX3NldHMgPSBTZW5lc2NlbmNlU2lnbmF0dXJlcykKCnNlbmVzY2VuY2VfdHJpZ2dlcnNfY29sb3JzIDwtIGMoCiAgIm5vbmUiID0gIiNFNTczNzMiLCAgIyBTb2Z0IHJlZCAgCiAgIlJhZGlhdGlvbiIgPSAiI0JEQkRCRCIsICAjIE1lZGl1bSBncmF5ICAKICAiRE5BIGRhbWFnZSIgPSAiIzY0QjVGNiIsICAjIEJyaWdodGVyIGJsdWUgIAogICJUZWxvbWVyZSBzaG9ydGVuaW5nIiA9ICIjNEZDM0Y3IiwgICMgVml2aWQgc2t5IGJsdWUgIAogICJETkEgZGVtZXRoeWxhdGlvbiIgPSAiI0JBNjhDOCIsICAjIFJpY2ggbGF2ZW5kZXIgIAogICJPeGlkYXRpdmUgc3RyZXNzIiA9ICIjRkREODM1IiwgICMgU3Ryb25nIHllbGxvdyAgCiAgIkNvbmRpdGlvbmVkIE1lZGl1bSIgPSAiI0YyOTk0QSIsICAjIFdhcm0gb3JhbmdlICAKICAiT25jb2dlbmUiID0gIiM4MUM3ODQiLCAgIyBNZWRpdW0gZ3JlZW4gIAogICJMaXBpZCBBY2N1bXVsYXRpb24iID0gIiNFNTczNzMiLCAgIyBDb3JhbCAgCiAgIkNhbGNpdW0gaW5mbHV4IiA9ICIjMjZBNjlBIiwgICMgRGVlcCB0ZWFsICAKICAiUGxhc21hIG1lbWJyYW5lIGR5c3J1cHRpb24iID0gIiNEMzJGMkYiLCAgIyBTdHJvbmcgc2FsbW9uICAKICAiT1NLTSBmYWN0b3JzIiA9ICIjRkZCNzREIiwgICMgQnJpZ2h0IHBlYWNoICAKICAiWUFQIEtPIiA9ICIjOTU3NUNEIiAgIyBEZWVwIHBhc3RlbCBwdXJwbGUgIAopCgpjZWxsVHlwZXNfY29sb3JzIDwtIGMoCiAgIkZpYnJvYmxhc3QiID0gIiNGRjY5NjEiLCAgICMgU3Ryb25nIFBhc3RlbCBSZWQgIAogICJLZXJhdGlub2N5dGUiID0gIiNGRkIzNDciLCAjIFN0cm9uZyBQYXN0ZWwgT3JhbmdlICAKICAiTWVsYW5vY3l0ZSIgPSAiI0ZGRDcwMCIsICAgIyBTdHJvbmcgUGFzdGVsIFllbGxvdyAgCiAgIkVuZG90aGVsaWFsIiA9ICIjNzdERDc3IiwgICMgU3Ryb25nIFBhc3RlbCBHcmVlbiAgCiAgIk5ldXJvbmFsIiA9ICIjNzc5RUNCIiwgICAgICMgU3Ryb25nIFBhc3RlbCBCbHVlICAKICAiTWVzZW5jaHltYWwiID0gIiNDMjdCQTAiICAgIyBTdHJvbmcgUGFzdGVsIFB1cnBsZSAgCikKCmNvbmRfY29oZW5kIDwtIGxpc3QoQT1jKCJTZW5lc2NlbnQiKSwgIyBpZiBubyB2YXJpYWJsZSBpcyBkZWZpbmVkLCB3aWxsIGJlIHRoZSBmaXJzdCB0aGF0IGFwcGVhcnMgaW4gdGhlIGdncGxvdAogICAgICAgICAgICAgICAgICAgIEI9YygiUHJvbGlmZXJhdGl2ZSIsIlF1aWVzY2VudCIpKQoKUGxvdFNjb3JlcyhSZXN1bHRzTGlzdCA9IGRmX3NzR1NFQSwgQ29sb3JWYXJpYWJsZSA9ICJDZWxsVHlwZSIsIEdyb3VwaW5nVmFyaWFibGU9IkNvbmRpdGlvbiIsICBtZXRob2QgPSJzc0dTRUEiLCBDb2xvclZhbHVlcyA9IGNlbGxUeXBlc19jb2xvcnMsIENvbm5lY3RHcm91cHM9VFJVRSwgbmNvbCA9IDYsIG5yb3cgPSAyLCB3aWR0aFRpdGxlPTIwLCB5X2xpbWl0cyA9IE5VTEwsIGxlZ2VuZF9ucm93ID0gMixjb25kX2NvaGVuZD1jb25kX2NvaGVuZCkKCmBgYAoKYGBge3IgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CmRmX2xvZ21lZGlhbiA8LSBDYWxjdWxhdGVTY29yZXMoZGF0YSA9IGNvcnJjb3VudHNfbWVyZ2UsIG1ldGFkYXRhID0gbWV0YWRhdGFfbWVyZ2UsIG1ldGhvZCA9ICJsb2dtZWRpYW4iLCBnZW5lX3NldHMgPSBTZW5lc2NlbmNlU2lnbmF0dXJlcykKCnNlbmVzY2VuY2VfdHJpZ2dlcnNfY29sb3JzIDwtIGMoCiAgIm5vbmUiID0gIiNFNTczNzMiLCAgIyBTb2Z0IHJlZCAgCiAgIlJhZGlhdGlvbiIgPSAiI0JEQkRCRCIsICAjIE1lZGl1bSBncmF5ICAKICAiRE5BIGRhbWFnZSIgPSAiIzY0QjVGNiIsICAjIEJyaWdodGVyIGJsdWUgIAogICJUZWxvbWVyZSBzaG9ydGVuaW5nIiA9ICIjNEZDM0Y3IiwgICMgVml2aWQgc2t5IGJsdWUgIAogICJETkEgZGVtZXRoeWxhdGlvbiIgPSAiI0JBNjhDOCIsICAjIFJpY2ggbGF2ZW5kZXIgIAogICJPeGlkYXRpdmUgc3RyZXNzIiA9ICIjRkREODM1IiwgICMgU3Ryb25nIHllbGxvdyAgCiAgIkNvbmRpdGlvbmVkIE1lZGl1bSIgPSAiI0YyOTk0QSIsICAjIFdhcm0gb3JhbmdlICAKICAiT25jb2dlbmUiID0gIiM4MUM3ODQiLCAgIyBNZWRpdW0gZ3JlZW4gIAogICJMaXBpZCBBY2N1bXVsYXRpb24iID0gIiNFNTczNzMiLCAgIyBDb3JhbCAgCiAgIkNhbGNpdW0gaW5mbHV4IiA9ICIjMjZBNjlBIiwgICMgRGVlcCB0ZWFsICAKICAiUGxhc21hIG1lbWJyYW5lIGR5c3J1cHRpb24iID0gIiNEMzJGMkYiLCAgIyBTdHJvbmcgc2FsbW9uICAKICAiT1NLTSBmYWN0b3JzIiA9ICIjRkZCNzREIiwgICMgQnJpZ2h0IHBlYWNoICAKICAiWUFQIEtPIiA9ICIjOTU3NUNEIiAgIyBEZWVwIHBhc3RlbCBwdXJwbGUgIAopCgpjZWxsVHlwZXNfY29sb3JzIDwtIGMoCiAgIkZpYnJvYmxhc3QiID0gIiNGRjY5NjEiLCAgICMgU3Ryb25nIFBhc3RlbCBSZWQgIAogICJLZXJhdGlub2N5dGUiID0gIiNGRkIzNDciLCAjIFN0cm9uZyBQYXN0ZWwgT3JhbmdlICAKICAiTWVsYW5vY3l0ZSIgPSAiI0ZGRDcwMCIsICAgIyBTdHJvbmcgUGFzdGVsIFllbGxvdyAgCiAgIkVuZG90aGVsaWFsIiA9ICIjNzdERDc3IiwgICMgU3Ryb25nIFBhc3RlbCBHcmVlbiAgCiAgIk5ldXJvbmFsIiA9ICIjNzc5RUNCIiwgICAgICMgU3Ryb25nIFBhc3RlbCBCbHVlICAKICAiTWVzZW5jaHltYWwiID0gIiNDMjdCQTAiICAgIyBTdHJvbmcgUGFzdGVsIFB1cnBsZSAgCikKCmNvbmRfY29oZW5kIDwtIGxpc3QoQT1jKCJTZW5lc2NlbnQiKSwgIyBpZiBubyB2YXJpYWJsZSBpcyBkZWZpbmVkLCB3aWxsIGJlIHRoZSBmaXJzdCB0aGF0IGFwcGVhcnMgaW4gdGhlIGdncGxvdAogICAgICAgICAgICAgICAgICAgIEI9YygiUHJvbGlmZXJhdGl2ZSIsIlF1aWVzY2VudCIpKQoKUGxvdFNjb3JlcyhSZXN1bHRzTGlzdCA9IGRmX2xvZ21lZGlhbiwgQ29sb3JWYXJpYWJsZSA9ICJDZWxsVHlwZSIsIEdyb3VwaW5nVmFyaWFibGU9IkNvbmRpdGlvbiIsICBtZXRob2QgPSJsb2dtZWRpYW4iLCBDb2xvclZhbHVlcyA9IGNlbGxUeXBlc19jb2xvcnMsIENvbm5lY3RHcm91cHM9VFJVRSwgbmNvbCA9IDYsIG5yb3cgPSAyLCB3aWR0aFRpdGxlPTIwLCB5X2xpbWl0cyA9IE5VTEwsIGxlZ2VuZF9ucm93ID0gMix4bGFiPU5VTEwsIGNvbmRfY29oZW5kID0gY29uZF9jb2hlbmQpCgpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02fQpkZl9yYW5raW5nIDwtIENhbGN1bGF0ZVNjb3JlcyhkYXRhID0gY29ycmNvdW50c19tZXJnZSwgbWV0YWRhdGEgPSBtZXRhZGF0YV9tZXJnZSwgbWV0aG9kID0gInJhbmtpbmciLCBnZW5lX3NldHMgPSBTZW5lc2NlbmNlU2lnbmF0dXJlcykKCnNlbmVzY2VuY2VfdHJpZ2dlcnNfY29sb3JzIDwtIGMoCiAgIm5vbmUiID0gIiNFNTczNzMiLCAgIyBTb2Z0IHJlZCAgCiAgIlJhZGlhdGlvbiIgPSAiI0JEQkRCRCIsICAjIE1lZGl1bSBncmF5ICAKICAiRE5BIGRhbWFnZSIgPSAiIzY0QjVGNiIsICAjIEJyaWdodGVyIGJsdWUgIAogICJUZWxvbWVyZSBzaG9ydGVuaW5nIiA9ICIjNEZDM0Y3IiwgICMgVml2aWQgc2t5IGJsdWUgIAogICJETkEgZGVtZXRoeWxhdGlvbiIgPSAiI0JBNjhDOCIsICAjIFJpY2ggbGF2ZW5kZXIgIAogICJPeGlkYXRpdmUgc3RyZXNzIiA9ICIjRkREODM1IiwgICMgU3Ryb25nIHllbGxvdyAgCiAgIkNvbmRpdGlvbmVkIE1lZGl1bSIgPSAiI0YyOTk0QSIsICAjIFdhcm0gb3JhbmdlICAKICAiT25jb2dlbmUiID0gIiM4MUM3ODQiLCAgIyBNZWRpdW0gZ3JlZW4gIAogICJMaXBpZCBBY2N1bXVsYXRpb24iID0gIiNFNTczNzMiLCAgIyBDb3JhbCAgCiAgIkNhbGNpdW0gaW5mbHV4IiA9ICIjMjZBNjlBIiwgICMgRGVlcCB0ZWFsICAKICAiUGxhc21hIG1lbWJyYW5lIGR5c3J1cHRpb24iID0gIiNEMzJGMkYiLCAgIyBTdHJvbmcgc2FsbW9uICAKICAiT1NLTSBmYWN0b3JzIiA9ICIjRkZCNzREIiwgICMgQnJpZ2h0IHBlYWNoICAKICAiWUFQIEtPIiA9ICIjOTU3NUNEIiAgIyBEZWVwIHBhc3RlbCBwdXJwbGUgIAopCgpjZWxsVHlwZXNfY29sb3JzIDwtIGMoCiAgIkZpYnJvYmxhc3QiID0gIiNGRjY5NjEiLCAgICMgU3Ryb25nIFBhc3RlbCBSZWQgIAogICJLZXJhdGlub2N5dGUiID0gIiNGRkIzNDciLCAjIFN0cm9uZyBQYXN0ZWwgT3JhbmdlICAKICAiTWVsYW5vY3l0ZSIgPSAiI0ZGRDcwMCIsICAgIyBTdHJvbmcgUGFzdGVsIFllbGxvdyAgCiAgIkVuZG90aGVsaWFsIiA9ICIjNzdERDc3IiwgICMgU3Ryb25nIFBhc3RlbCBHcmVlbiAgCiAgIk5ldXJvbmFsIiA9ICIjNzc5RUNCIiwgICAgICMgU3Ryb25nIFBhc3RlbCBCbHVlICAKICAiTWVzZW5jaHltYWwiID0gIiNDMjdCQTAiICAgIyBTdHJvbmcgUGFzdGVsIFB1cnBsZSAgCikKCmNvbmRfY29oZW5kIDwtIGxpc3QoQT1jKCJTZW5lc2NlbnQiKSwgIyBpZiBubyB2YXJpYWJsZSBpcyBkZWZpbmVkLCB3aWxsIGJlIHRoZSBmaXJzdCB0aGF0IGFwcGVhcnMgaW4gdGhlIGdncGxvdAogICAgICAgICAgICAgICAgICAgIEI9YygiUHJvbGlmZXJhdGl2ZSIsIlF1aWVzY2VudCIpKQoKUGxvdFNjb3JlcyhSZXN1bHRzTGlzdCA9IGRmX3JhbmtpbmcsIENvbG9yVmFyaWFibGUgPSAiQ2VsbFR5cGUiLCBHcm91cGluZ1ZhcmlhYmxlPSJDb25kaXRpb24iLCAgbWV0aG9kID0icmFua2luZyIsIENvbG9yVmFsdWVzID0gY2VsbFR5cGVzX2NvbG9ycywgQ29ubmVjdEdyb3Vwcz1UUlVFLCBuY29sID0gNiwgbnJvdyA9IDIsIHdpZHRoVGl0bGU9MjAsIHlfbGltaXRzID0gTlVMTCwgbGVnZW5kX25yb3cgPSAyLHhsYWI9TlVMTCwgY29uZF9jb2hlbmQgPSBjb25kX2NvaGVuZCkKCmBgYAoKCmBgYHtyIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQoKcGxvdGxpc3QgPC0gbGlzdCgpCgpmb3IgKHNpZyBpbiBuYW1lcyhkZl9zc0dTRUEpKXsKICAKICBkZl9zdWJzZXRfc3NHU0VBIDwtIGRmX3NzR1NFQVtbc2lnXV0KICBkZl9zdWJzZXRfbG9nbWVkaWFuIDwtIGRmX2xvZ21lZGlhbltbc2lnXV0KICAKICBkZl9zdWJzZXRfbWVyZ2UgPC0gbWVyZ2UoZGZfc3Vic2V0X3NzR1NFQSxkZl9zdWJzZXRfbG9nbWVkaWFuLGJ5PSJzYW1wbGUiKQogIAogICMgV3JhcCB0aGUgc2lnbmF0dXJlIG5hbWUgdXNpbmcgdGhlIGhlbHBlciBmdW5jdGlvbgogIHdyYXBwZWRfdGl0bGUgPC0gd3JhcF90aXRsZV9hdXgoc2lnLCB3aWR0aCA9IDIwKSAgCiAgCiAgcGxvdGxpc3RbW3NpZ11dIDwtIGdncGxvdDI6OmdncGxvdChkZl9zdWJzZXRfbWVyZ2UsIGFlcyh4PXNjb3JlLngsIHk9c2NvcmUueSkpICsKICAgIGdlb21fcG9pbnQoc2l6ZT00LCBhbHBoYT0wLjgsIGZpbGw9ImRhcmtncmV5Iiwgc2hhcGU9MjEpICsKICAgIHRoZW1lX2J3KCkgKwogICAgeGxhYigic3NHU0VBIEVucmljaG1lbnQgU2NvcmUiKSArCiAgICB5bGFiKCJOb3JtYWxpc2VkIFNpZ25hdHVyZSBTY29yZSIpICsKICAgIGdndGl0bGUod3JhcHBlZF90aXRsZSkgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZT0xMCksCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgCiAgCn0KCmdncHVicjo6Z2dhcnJhbmdlKHBsb3RsaXN0PXBsb3RsaXN0LCBucm93PTMsIG5jb2w9NCwgYWxpZ24gPSAiaCIpCmBgYAoKIyMgQmlkaXJlY3Rpb25hbCBnZW5lIHNpZ25hdHVyZXMKClRyeSBzY29yZXMgd2l0aCBiaWRpcmVjdGlvbmFsIHNpZ25hdHVyZXMKCmBgYHtyfQpiaWRpcmVjdHNpZ3MgPC0gcmVhZFJEUygifi9WZXJzaW9uQ29udHJvbC9zZW5lc2NlbmNlX2JlbmNobWFya2luZy9Db21tb25GaWxlcy9TZW5lc2NlbmNlU2lnbmF0dXJlc19jb21wbGV0ZV9uZXdDZWxsQWdlLlJEUyIpCmZvciAoc2lnIGluIG5hbWVzKGJpZGlyZWN0c2lncykpewogIHNpZ2RmIDwtIGJpZGlyZWN0c2lnc1tbc2lnXV0KICBzaWdkZiA8LSBzaWdkZlssMToyXSAjIHJlbW92ZSB0aGUgdGhpcmQgY29sdW1uLCBpZiBhcHBsaWNhYmxlCiAgaWYoYW55KHNpZ2RmWywyXT09Im5vdF9yZXBvcnRlZCIpKXsKICAgIHNpZ2RmIDwtIHNpZ2RmWywxXQogICAgYmlkaXJlY3RzaWdzW1tzaWddXSA8LSBzaWdkZgogICAgbmV4dCAKICB9CiAgc2lnZGZbLDJdIDwtIGlmZWxzZShzaWdkZlssMl09PSJlbnJpY2hlZCIsMSwtMSkKICBiaWRpcmVjdHNpZ3NbW3NpZ11dIDwtIHNpZ2RmCn0KYmlkaXJlY3RzaWdzCgpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTEwfQpkZl9sb2dtZWRpYW4gPC0gQ2FsY3VsYXRlU2NvcmVzKGRhdGEgPSBjb3JyY291bnRzX21lcmdlLCBtZXRhZGF0YSA9IG1ldGFkYXRhX21lcmdlLCBtZXRob2QgPSAibG9nbWVkaWFuIiwgZ2VuZV9zZXRzID0gYmlkaXJlY3RzaWdzKQoKc2VuZXNjZW5jZV90cmlnZ2Vyc19jb2xvcnMgPC0gYygKICAibm9uZSIgPSAiI0U1NzM3MyIsICAjIFNvZnQgcmVkICAKICAiUmFkaWF0aW9uIiA9ICIjQkRCREJEIiwgICMgTWVkaXVtIGdyYXkgIAogICJETkEgZGFtYWdlIiA9ICIjNjRCNUY2IiwgICMgQnJpZ2h0ZXIgYmx1ZSAgCiAgIlRlbG9tZXJlIHNob3J0ZW5pbmciID0gIiM0RkMzRjciLCAgIyBWaXZpZCBza3kgYmx1ZSAgCiAgIkROQSBkZW1ldGh5bGF0aW9uIiA9ICIjQkE2OEM4IiwgICMgUmljaCBsYXZlbmRlciAgCiAgIk94aWRhdGl2ZSBzdHJlc3MiID0gIiNGREQ4MzUiLCAgIyBTdHJvbmcgeWVsbG93ICAKICAiQ29uZGl0aW9uZWQgTWVkaXVtIiA9ICIjRjI5OTRBIiwgICMgV2FybSBvcmFuZ2UgIAogICJPbmNvZ2VuZSIgPSAiIzgxQzc4NCIsICAjIE1lZGl1bSBncmVlbiAgCiAgIkxpcGlkIEFjY3VtdWxhdGlvbiIgPSAiI0U1NzM3MyIsICAjIENvcmFsICAKICAiQ2FsY2l1bSBpbmZsdXgiID0gIiMyNkE2OUEiLCAgIyBEZWVwIHRlYWwgIAogICJQbGFzbWEgbWVtYnJhbmUgZHlzcnVwdGlvbiIgPSAiI0QzMkYyRiIsICAjIFN0cm9uZyBzYWxtb24gIAogICJPU0tNIGZhY3RvcnMiID0gIiNGRkI3NEQiLCAgIyBCcmlnaHQgcGVhY2ggIAogICJZQVAgS08iID0gIiM5NTc1Q0QiICAjIERlZXAgcGFzdGVsIHB1cnBsZSAgCikKCmNlbGxUeXBlc19jb2xvcnMgPC0gYygKICAiRmlicm9ibGFzdCIgPSAiI0ZGNjk2MSIsICAgIyBTdHJvbmcgUGFzdGVsIFJlZCAgCiAgIktlcmF0aW5vY3l0ZSIgPSAiI0ZGQjM0NyIsICMgU3Ryb25nIFBhc3RlbCBPcmFuZ2UgIAogICJNZWxhbm9jeXRlIiA9ICIjRkZENzAwIiwgICAjIFN0cm9uZyBQYXN0ZWwgWWVsbG93ICAKICAiRW5kb3RoZWxpYWwiID0gIiM3N0RENzciLCAgIyBTdHJvbmcgUGFzdGVsIEdyZWVuICAKICAiTmV1cm9uYWwiID0gIiM3NzlFQ0IiLCAgICAgIyBTdHJvbmcgUGFzdGVsIEJsdWUgIAogICJNZXNlbmNoeW1hbCIgPSAiI0MyN0JBMCIgICAjIFN0cm9uZyBQYXN0ZWwgUHVycGxlICAKKQoKY29uZF9jb2hlbmQgPC0gbGlzdChBPWMoIlNlbmVzY2VudCIpLCAjIGlmIG5vIHZhcmlhYmxlIGlzIGRlZmluZWQsIHdpbGwgYmUgdGhlIGZpcnN0IHRoYXQgYXBwZWFycyBpbiB0aGUgZ2dwbG90CiAgICAgICAgICAgICAgICAgICAgQj1jKCJQcm9saWZlcmF0aXZlIiwiUXVpZXNjZW50IikpCgpQbG90U2NvcmVzKFJlc3VsdHNMaXN0ID0gZGZfbG9nbWVkaWFuLCBDb2xvclZhcmlhYmxlID0gIkNlbGxUeXBlIiwgR3JvdXBpbmdWYXJpYWJsZT0iQ29uZGl0aW9uIiwgIG1ldGhvZCA9ImxvZ21lZGlhbiIsIENvbG9yVmFsdWVzID0gY2VsbFR5cGVzX2NvbG9ycywgQ29ubmVjdEdyb3Vwcz1UUlVFLCBuY29sID0gMywgbnJvdyA9IDMsIHdpZHRoVGl0bGU9MjAsIHlfbGltaXRzID0gTlVMTCwgbGVnZW5kX25yb3cgPSAyLHhsYWI9TlVMTCwgY29uZF9jb2hlbmQgPSBjb25kX2NvaGVuZCkKCmBgYAoKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTEwfQoKZGZfc3Nnc2VhIDwtIENhbGN1bGF0ZVNjb3JlcyhkYXRhID0gY29ycmNvdW50c19tZXJnZSwgbWV0YWRhdGEgPSBtZXRhZGF0YV9tZXJnZSwgbWV0aG9kID0gInNzR1NFQSIsIGdlbmVfc2V0cyA9IGJpZGlyZWN0c2lncykKCnNlbmVzY2VuY2VfdHJpZ2dlcnNfY29sb3JzIDwtIGMoCiAgIm5vbmUiID0gIiNFNTczNzMiLCAgIyBTb2Z0IHJlZCAgCiAgIlJhZGlhdGlvbiIgPSAiI0JEQkRCRCIsICAjIE1lZGl1bSBncmF5ICAKICAiRE5BIGRhbWFnZSIgPSAiIzY0QjVGNiIsICAjIEJyaWdodGVyIGJsdWUgIAogICJUZWxvbWVyZSBzaG9ydGVuaW5nIiA9ICIjNEZDM0Y3IiwgICMgVml2aWQgc2t5IGJsdWUgIAogICJETkEgZGVtZXRoeWxhdGlvbiIgPSAiI0JBNjhDOCIsICAjIFJpY2ggbGF2ZW5kZXIgIAogICJPeGlkYXRpdmUgc3RyZXNzIiA9ICIjRkREODM1IiwgICMgU3Ryb25nIHllbGxvdyAgCiAgIkNvbmRpdGlvbmVkIE1lZGl1bSIgPSAiI0YyOTk0QSIsICAjIFdhcm0gb3JhbmdlICAKICAiT25jb2dlbmUiID0gIiM4MUM3ODQiLCAgIyBNZWRpdW0gZ3JlZW4gIAogICJMaXBpZCBBY2N1bXVsYXRpb24iID0gIiNFNTczNzMiLCAgIyBDb3JhbCAgCiAgIkNhbGNpdW0gaW5mbHV4IiA9ICIjMjZBNjlBIiwgICMgRGVlcCB0ZWFsICAKICAiUGxhc21hIG1lbWJyYW5lIGR5c3J1cHRpb24iID0gIiNEMzJGMkYiLCAgIyBTdHJvbmcgc2FsbW9uICAKICAiT1NLTSBmYWN0b3JzIiA9ICIjRkZCNzREIiwgICMgQnJpZ2h0IHBlYWNoICAKICAiWUFQIEtPIiA9ICIjOTU3NUNEIiAgIyBEZWVwIHBhc3RlbCBwdXJwbGUgIAopCgpjZWxsVHlwZXNfY29sb3JzIDwtIGMoCiAgIkZpYnJvYmxhc3QiID0gIiNGRjY5NjEiLCAgICMgU3Ryb25nIFBhc3RlbCBSZWQgIAogICJLZXJhdGlub2N5dGUiID0gIiNGRkIzNDciLCAjIFN0cm9uZyBQYXN0ZWwgT3JhbmdlICAKICAiTWVsYW5vY3l0ZSIgPSAiI0ZGRDcwMCIsICAgIyBTdHJvbmcgUGFzdGVsIFllbGxvdyAgCiAgIkVuZG90aGVsaWFsIiA9ICIjNzdERDc3IiwgICMgU3Ryb25nIFBhc3RlbCBHcmVlbiAgCiAgIk5ldXJvbmFsIiA9ICIjNzc5RUNCIiwgICAgICMgU3Ryb25nIFBhc3RlbCBCbHVlICAKICAiTWVzZW5jaHltYWwiID0gIiNDMjdCQTAiICAgIyBTdHJvbmcgUGFzdGVsIFB1cnBsZSAgCikKCmNvbmRfY29oZW5kIDwtIGxpc3QoQT1jKCJTZW5lc2NlbnQiKSwgIyBpZiBubyB2YXJpYWJsZSBpcyBkZWZpbmVkLCB3aWxsIGJlIHRoZSBmaXJzdCB0aGF0IGFwcGVhcnMgaW4gdGhlIGdncGxvdAogICAgICAgICAgICAgICAgICAgIEI9YygiUHJvbGlmZXJhdGl2ZSIsIlF1aWVzY2VudCIpKQoKUGxvdFNjb3JlcyhSZXN1bHRzTGlzdCA9IGRmX3NzZ3NlYSwgQ29sb3JWYXJpYWJsZSA9ICJDZWxsVHlwZSIsIEdyb3VwaW5nVmFyaWFibGU9IkNvbmRpdGlvbiIsICBtZXRob2QgPSJzc0dTRUEiLCBDb2xvclZhbHVlcyA9IGNlbGxUeXBlc19jb2xvcnMsIENvbm5lY3RHcm91cHM9VFJVRSwgbmNvbCA9IDMsIG5yb3cgPSAzLCB3aWR0aFRpdGxlPTIwLCB5X2xpbWl0cyA9IE5VTEwsIGxlZ2VuZF9ucm93ID0gMix4bGFiPU5VTEwsIGNvbmRfY29oZW5kID0gY29uZF9jb2hlbmQpCgpgYGAKCgoKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTEwfQoKZGZfcmFua2luZyA8LSBDYWxjdWxhdGVTY29yZXMoZGF0YSA9IGNvcnJjb3VudHNfbWVyZ2UsIG1ldGFkYXRhID0gbWV0YWRhdGFfbWVyZ2UsIG1ldGhvZCA9ICJyYW5raW5nIiwgZ2VuZV9zZXRzID0gYmlkaXJlY3RzaWdzKQoKc2VuZXNjZW5jZV90cmlnZ2Vyc19jb2xvcnMgPC0gYygKICAibm9uZSIgPSAiI0U1NzM3MyIsICAjIFNvZnQgcmVkICAKICAiUmFkaWF0aW9uIiA9ICIjQkRCREJEIiwgICMgTWVkaXVtIGdyYXkgIAogICJETkEgZGFtYWdlIiA9ICIjNjRCNUY2IiwgICMgQnJpZ2h0ZXIgYmx1ZSAgCiAgIlRlbG9tZXJlIHNob3J0ZW5pbmciID0gIiM0RkMzRjciLCAgIyBWaXZpZCBza3kgYmx1ZSAgCiAgIkROQSBkZW1ldGh5bGF0aW9uIiA9ICIjQkE2OEM4IiwgICMgUmljaCBsYXZlbmRlciAgCiAgIk94aWRhdGl2ZSBzdHJlc3MiID0gIiNGREQ4MzUiLCAgIyBTdHJvbmcgeWVsbG93ICAKICAiQ29uZGl0aW9uZWQgTWVkaXVtIiA9ICIjRjI5OTRBIiwgICMgV2FybSBvcmFuZ2UgIAogICJPbmNvZ2VuZSIgPSAiIzgxQzc4NCIsICAjIE1lZGl1bSBncmVlbiAgCiAgIkxpcGlkIEFjY3VtdWxhdGlvbiIgPSAiI0U1NzM3MyIsICAjIENvcmFsICAKICAiQ2FsY2l1bSBpbmZsdXgiID0gIiMyNkE2OUEiLCAgIyBEZWVwIHRlYWwgIAogICJQbGFzbWEgbWVtYnJhbmUgZHlzcnVwdGlvbiIgPSAiI0QzMkYyRiIsICAjIFN0cm9uZyBzYWxtb24gIAogICJPU0tNIGZhY3RvcnMiID0gIiNGRkI3NEQiLCAgIyBCcmlnaHQgcGVhY2ggIAogICJZQVAgS08iID0gIiM5NTc1Q0QiICAjIERlZXAgcGFzdGVsIHB1cnBsZSAgCikKCmNlbGxUeXBlc19jb2xvcnMgPC0gYygKICAiRmlicm9ibGFzdCIgPSAiI0ZGNjk2MSIsICAgIyBTdHJvbmcgUGFzdGVsIFJlZCAgCiAgIktlcmF0aW5vY3l0ZSIgPSAiI0ZGQjM0NyIsICMgU3Ryb25nIFBhc3RlbCBPcmFuZ2UgIAogICJNZWxhbm9jeXRlIiA9ICIjRkZENzAwIiwgICAjIFN0cm9uZyBQYXN0ZWwgWWVsbG93ICAKICAiRW5kb3RoZWxpYWwiID0gIiM3N0RENzciLCAgIyBTdHJvbmcgUGFzdGVsIEdyZWVuICAKICAiTmV1cm9uYWwiID0gIiM3NzlFQ0IiLCAgICAgIyBTdHJvbmcgUGFzdGVsIEJsdWUgIAogICJNZXNlbmNoeW1hbCIgPSAiI0MyN0JBMCIgICAjIFN0cm9uZyBQYXN0ZWwgUHVycGxlICAKKQoKY29uZF9jb2hlbmQgPC0gbGlzdChBPWMoIlNlbmVzY2VudCIpLCAjIGlmIG5vIHZhcmlhYmxlIGlzIGRlZmluZWQsIHdpbGwgYmUgdGhlIGZpcnN0IHRoYXQgYXBwZWFycyBpbiB0aGUgZ2dwbG90CiAgICAgICAgICAgICAgICAgICAgQj1jKCJQcm9saWZlcmF0aXZlIiwiUXVpZXNjZW50IikpCgpQbG90U2NvcmVzKFJlc3VsdHNMaXN0ID0gZGZfcmFua2luZywgQ29sb3JWYXJpYWJsZSA9ICJDZWxsVHlwZSIsIEdyb3VwaW5nVmFyaWFibGU9IkNvbmRpdGlvbiIsICBtZXRob2QgPSJyYW5raW5nIiwgQ29sb3JWYWx1ZXMgPSBjZWxsVHlwZXNfY29sb3JzLCBDb25uZWN0R3JvdXBzPVRSVUUsIG5jb2wgPSAzLCBucm93ID0gMywgd2lkdGhUaXRsZT0yMCwgeV9saW1pdHMgPSBOVUxMLCBsZWdlbmRfbnJvdyA9IDIseGxhYj1OVUxMLCBjb25kX2NvaGVuZCA9IGNvbmRfY29oZW5kKQoKYGBgCgoKCiMjIEhlYXRtYXAgZm9yIENvaGVuJ3MgRAoKCgoKYGBge3IgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTEyfQoKUGxvdFNjb3JlcyhkYXRhID0gY29ycmNvdW50c19tZXJnZSwgCiAgICAgICAgICAgbWV0YWRhdGEgPSBtZXRhZGF0YV9tZXJnZSwgIAogICAgICAgICAgIGdlbmVfc2V0cz1iaWRpcmVjdHNpZ3MsIAogICAgICAgICAgIEdyb3VwaW5nVmFyaWFibGU9IkNvbmRpdGlvbiIsICAKICAgICAgICAgICBtZXRob2QgPSJhbGwiLCAgIAogICAgICAgICAgIG5jb2wgPSBOVUxMLCAKICAgICAgICAgICBucm93ID0gTlVMTCwgCiAgICAgICAgICAgd2lkdGhUaXRsZT0zMCwgCiAgICAgICAgICAgbGltaXRzID0gTlVMTCwgICAKICAgICAgICAgICB0aXRsZT0iTWFydGhhbmRhbiBldCBhbC4gMjAxNiIsIAogICAgICAgICAgIHRpdGxlc2l6ZSA9IDEyLAogICAgICAgICAgIENvbG9yVmFsdWVzID0gTlVMTCkgIAoKCiMgbWlzc2luZzogCiMgLSBjb21iaW5lIGxlZ2VuZHMKIyAtIHdyYXAgdGl0bGUKIyAtIHRpbHQgeCBsYWJlbHMgdG8gNjAgZGVncmVlcwojIC0gY2hhbmdlIGRlZmF1bHQgY29sb3JzCiMgd3JhcCB4IGxhYmVscyB3aXRoIHdyYXBfdGl0bGUKIyBncmlkIHdpdGggY29tbW9uIGxlZ2VuZHMgaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvcC84NzMxOC8KCgpgYGAKCgojIyBDb3JyZWxhdGlvbiBwbG90cwoKSWYgdGhlIHVzZXIgaXMgaW52ZXN0aWdhdGluZyBpZiBhIGNlcnRhaW4gdmFyaWFibGUgY2FuIGJlIGRlc2NyaWJlZCBmcm9tIHRoZSBzY29yZSwgYW5kIG5vdCBhbHJlYWR5IGtub3dpbmcgdGhhdCB2YXJpYWJsZS4gTW9yZSBleHBsb3JhdG9yeS4uLgoKLSBEZWZpbmUgd2hhdCBlYWNoIHZhcmlhYmxlIGlzOiBOdW1lcmljIChpbmNsdWRlcyBpbnRlZ2VyIGlmIHVuaXF1ZSA+IDUpLCBDYXRlZ29yaWNhbCBCaW4gKGludGVnZXIvc3RyaW5nIGlmIHVuaXF1ZSA9PSAyLCBsb2dpY2FsKSwgQ2F0ZWdvcmljYWwgTXVsdGkgKGludGVnZXIgaWYgdW5pcXVlIDwgNSwgc3RyaW5nIGlmIHVuaXF1ZSA+IDIpCi0gRGVmaW5lIGZ1bmN0aW9ucyB0byBjYWxjdWxhdGUgbWV0cmljcyBiYXNlZCBvbiBkaWZmZXJlbnQgZGF0YSB0eXBlczogCiAgIC0gQ2F0ZWdvcmljYWwgQmluOiB0LXRlc3Qvd2lsY294b24KICAgLSBDYXRlZ29yaWNhbCBNdWx0aTogQU5PVkEgLyBLcnVza2FsLVdhbGxpcyArIFR1a2V5J3MgdGVzdCAKICAgLSBOdW1lcmljIDogUGVhcnNvbiAvIFNwZWFybWFuIC8gS2VuZGFsbCdzIFRhdQotIFJldHVybiBhIGxpc3Q6CiAgIC0gT25lIGVudHJ5IHBlciB2YXJpYWJsZQogICAgICAgLSBNZXRob2QgdXNlZAogICAgICAgLSBEYXRhIGZyYW1lCiAgICAgICAgICAgLSBUd28gY29sdW1uczogbWV0cmljIGFuZCBwLXZhbHVlCiAgICAgICAgICAgLSBPbmUgbGluZSBwZXIgc3VidmFyaWFibGUgKGlmIE51bWVyaWMgYW5kIENhdGVnb3JpY2FsIEJpbiwgb25seSBvbmUgbGluZTsgZm9yIENhdGVnb3JpY2FsIE11bHRpLCBvbmUgcGVyIGNvbWJpbmF0aW9uIG9mIHZhcmlhYmxlcyk7IG5hbWVkIHJvd3MKLSBQbG90IHJlc3VsdHMKICAgIC0gSWYgTnVtZXJpYywgc2NhdHRlciBwbG90OyBtZXRyaWMgb24gdGhlIHRvcCBsZWZ0IGNvcm5lcgogICAgLSBJZiBDYXRlZ29yaWNhbCwgZGVuc2l0eSBwbG90LCBjb2xvcmVkIGJ5IHRoZSB1bmlxdWUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZTsgbWV0cmljcyAoaWYgb25lLCBvciBjb21iaW5hdGlvbnMgb2YgdmFyaWFibGVzKSBpbiB0b3AgbGVmdCBjb3JuZXIKICAgIC0gQXJyYW5nZSBpbiBncmlkCgpgYGB7cn0KbWV0YWRhdGFfY29yciA8LSBDYWxjdWxhdGVTY29yZXMoZGF0YSA9IGNvcnJjb3VudHNfbWVyZ2UsIG1ldGFkYXRhID0gbWV0YWRhdGFfbWVyZ2VfY29yciwgbWV0aG9kID0gInNzR1NFQSIsIGdlbmVfc2V0cyA9IGxpc3QoSGVybmFuZGV6U2VndXJhX1VQPSBTZW5lc2NlbmNlU2lnbmF0dXJlcyRgW1VQXV9IZXJuYW5kZXpTZWd1cmFgKSkKbWV0YWRhdGFfY29yciA8LSBtZXRhZGF0YV9jb3JyJEhlcm5hbmRlelNlZ3VyYV9VUApgYGAKCmBgYHtyIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD0zfQpvcHRpb25zKGVycm9yPXJlY292ZXIpCnBsb3Rfc3RhdF90ZXN0cyhtZXRhZGF0YV9jb3JyLCB0YXJnZXRfdmFyPSJzY29yZSIsIGNvbHMgPSBjKCJDb25kaXRpb24iLCJJc19TZW5lc2NlbnQiLCJyYW5kb21fY2F0IiwicmFuZG9tX251bWVyaWMiKSwKICAgICAgICAgICAgICAgICBkaXNjcmV0ZV9jb2xvcnMgPSBsaXN0KElzX1NlbmVzY2VudD1jKCJTZW5lc2NlbnQiPSJwaW5rIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb24gU2VuZXNjZW50Ij0ib3JhbmdlIikpLCAKICAgICAgICAgICAgICAgIGNvbnRpbnVvdXNfY29sb3IgPSAiIzhDNkQwMyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JfcGFsZXR0ZSA9ICJTZXQyIiwgbnJvdz0xLCBzaXplYW5ub3Q9MywgbGVnZW5kLnBvc2l0aW9uPSJ0b3AiKQpgYGAKCgojIEluZGl2aWR1YWwgR2VuZXMKCiMjIyBWaW9saW4gRXhwcmVzc2lvbiBQbG90cwoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KCgpzZW5lc2NlbmNlX3RyaWdnZXJzX2NvbG9ycyA8LSBjKAogICJub25lIiA9ICIjRTU3MzczIiwgICMgU29mdCByZWQgIAogICJSYWRpYXRpb24iID0gIiNCREJEQkQiLCAgIyBNZWRpdW0gZ3JheSAgCiAgIkROQSBkYW1hZ2UiID0gIiM2NEI1RjYiLCAgIyBCcmlnaHRlciBibHVlICAKICAiVGVsb21lcmUgc2hvcnRlbmluZyIgPSAiIzRGQzNGNyIsICAjIFZpdmlkIHNreSBibHVlICAKICAiRE5BIGRlbWV0aHlsYXRpb24iID0gIiNCQTY4QzgiLCAgIyBSaWNoIGxhdmVuZGVyICAKICAiT3hpZGF0aXZlIHN0cmVzcyIgPSAiI0ZERDgzNSIsICAjIFN0cm9uZyB5ZWxsb3cgIAogICJDb25kaXRpb25lZCBNZWRpdW0iID0gIiNGMjk5NEEiLCAgIyBXYXJtIG9yYW5nZSAgCiAgIk9uY29nZW5lIiA9ICIjODFDNzg0IiwgICMgTWVkaXVtIGdyZWVuICAKICAiTGlwaWQgQWNjdW11bGF0aW9uIiA9ICIjRTU3MzczIiwgICMgQ29yYWwgIAogICJDYWxjaXVtIGluZmx1eCIgPSAiIzI2QTY5QSIsICAjIERlZXAgdGVhbCAgCiAgIlBsYXNtYSBtZW1icmFuZSBkeXNydXB0aW9uIiA9ICIjRDMyRjJGIiwgICMgU3Ryb25nIHNhbG1vbiAgCiAgIk9TS00gZmFjdG9ycyIgPSAiI0ZGQjc0RCIsICAjIEJyaWdodCBwZWFjaCAgCiAgIllBUCBLTyIgPSAiIzk1NzVDRCIgICMgRGVlcCBwYXN0ZWwgcHVycGxlICAKKQoKCkluZGl2aWR1YWxHZW5lc19WaW9saW5zKGRhdGEgPSBjb3JyY291bnRzX21lcmdlLCBtZXRhZGF0YSA9IG1ldGFkYXRhX21lcmdlLCBnZW5lcyA9IGMoIkNES04xQSIsICJDREtOMkEiLCAiR0xCMSIsIlRQNTMiLCJDQ0wyIiksIEdyb3VwaW5nVmFyaWFibGUgPSAiQ29uZGl0aW9uIiwgcGxvdD1ULCBuY29sPU5VTEwsIG5yb3c9MiwgZGl2aWRlPSJDZWxsVHlwZSIsIGludmVydF9kaXZpZGU9RkFMU0UsQ29sb3JWYWx1ZXM9c2VuZXNjZW5jZV90cmlnZ2Vyc19jb2xvcnMsIHBvaW50U2l6ZT0yLCBDb2xvclZhcmlhYmxlPSJTZW5lc2NlbnRUeXBlIiwgdGl0bGU9IlNlbmVzY2VuY2UiLCB3aWR0aFRpdGxlPTE2LHlfbGltaXRzID0gTlVMTCxsZWdlbmRfbnJvdz00LCB4bGFiPSJDb25kaXRpb24iLGNvbG9ybGFiPSIiKSAKYGBgCgoKCiMjIyBDb3JyZWxhdGlvbiBIZWF0bWFwCgoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0Kb3B0aW9ucyhlcnJvcj1yZWNvdmVyKQpDb3JyZWxhdGlvbkhlYXRtYXAoZGF0YT1jb3JyY291bnRzX21lcmdlLCAKICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhID0gbWV0YWRhdGFfbWVyZ2UsIAogICAgICAgICAgICAgICAgICAgZ2VuZXM9YygiQ0RLTjFBIiwgIkNES04yQSIsICJHTEIxIiwiVFA1MyIsIkNDTDIiKSwgCiAgICAgICAgICAgICAgICAgICBzZXBhcmF0ZS5ieSA9ICJDb25kaXRpb24iLCAKICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIiwgIAogICAgICAgICAgICAgICAgICAgY29sb3JsaXN0ID0gbGlzdChsb3cgPSAiIzNGNDE5MyIsIG1pZCA9ICIjRjlGNEFFIiwgaGlnaCA9ICIjQjQ0MTQxIiksCiAgICAgICAgICAgICAgICAgICBsaW1pdHNfY29sb3JzY2FsZSA9IGMoLTEsMCwxKSwgCiAgICAgICAgICAgICAgICAgICB3aWR0aFRpdGxlID0gMTYsIAogICAgICAgICAgICAgICAgICAgdGl0bGUgPSAidGVzdCIsIAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLCAgCiAgICAgICAgICAgICAgICAgICBkZXRhaWxlZHJlc3VsdHMgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICBsZWdlbmRfcG9zaXRpb249InJpZ2h0IiwKICAgICAgICAgICAgICAgICAgIHRpdGxlc2l6ZT0yMCkKCgpgYGAKCgoKCiMjIyBFeHByZXNzaW9uIEhlYXRtYXBzCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0Kb3B0aW9ucyhlcnJvcj1yZWNvdmVyKQoKYW5ub3RhdGlvbl9jb2xvcnMgPC0gbGlzdCgKICBDZWxsVHlwZSA9IGMoCiAgICAiRmlicm9ibGFzdCIgICA9ICIjRkY2OTYxIiwgICAjIFN0cm9uZyBQYXN0ZWwgUmVkICAKICAgICJLZXJhdGlub2N5dGUiID0gIiNGRkIzNDciLCAgICMgU3Ryb25nIFBhc3RlbCBPcmFuZ2UgIAogICAgIk1lbGFub2N5dGUiICAgPSAiI0ZGRDcwMCIsICAgIyBTdHJvbmcgUGFzdGVsIFllbGxvdyAgCiAgICAiRW5kb3RoZWxpYWwiICA9ICIjNzdERDc3IiwgICAjIFN0cm9uZyBQYXN0ZWwgR3JlZW4gIAogICAgIk5ldXJvbmFsIiAgICAgPSAiIzc3OUVDQiIsICAgIyBTdHJvbmcgUGFzdGVsIEJsdWUgIAogICAgIk1lc2VuY2h5bWFsIiAgPSAiI0MyN0JBMCIgICAgIyBTdHJvbmcgUGFzdGVsIFB1cnBsZSAgCiAgKSwKICBDb25kaXRpb24gPSBjKAogICAgIlNlbmVzY2VudCIgICAgID0gIiM2NUFDN0MiLCAgIyBFeGFtcGxlIGNvbG9yOiBncmVlbmlzaAogICAgIlByb2xpZmVyYXRpdmUiID0gIiM1RjkwRDQiLCAgIyBFeGFtcGxlIGNvbG9yOiBibHVlaXNoCiAgICAiUXVpZXNjZW50IiAgICAgPSAiI0VEQTAzRSIgICAjIEV4YW1wbGUgY29sb3I6IG9yYW5nZQogICkKKQoKRXhwcmVzc2lvbkhlYXRtYXAoZGF0YT1jb3JyY291bnRzX21lcmdlLCAKICAgICAgICAgICAgICAgICAgbWV0YWRhdGEgPSBtZXRhZGF0YV9tZXJnZSwgCiAgICAgICAgICAgICAgICAgIGdlbmVzPWMoIkNES04xQSIsICJDREtOMkEiLCAiR0xCMSIsIlRQNTMiLCJDQ0wyIiksICAKICAgICAgICAgICAgICAgICAgYW5ub3RhdGUuYnkgPSBjKCJDZWxsVHlwZSIsIkNvbmRpdGlvbiIpLAogICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3JzLAogICAgICAgICAgICAgICAgICBjb2xvcmxpc3QgPSBsaXN0KGxvdyA9ICIjM0Y0MTkzIiwgbWlkID0gIiNGOUY0QUUiLCBoaWdoID0gIiNCNDQxNDEiKSwKICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICB0aXRsZSA9ICJ0ZXN0IiwgCiAgICAgICAgICAgICAgICAgIHRpdGxlc2l6ZSA9IDIwLAogICAgICAgICAgICAgICAgICBsZWdlbmRfcG9zaXRpb24gPSAicmlnaHQiLAogICAgICAgICAgICAgICAgICBzY2FsZV9wb3NpdGlvbj0icmlnaHQiKQoKYGBgCgoKCiMjIyBST0MvQVVDIAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9CgpjZWxsVHlwZXNfY29sb3JzIDwtIGMoCiAgIkZpYnJvYmxhc3QiID0gIiNGRjY5NjEiLCAgICMgU3Ryb25nIFBhc3RlbCBSZWQgIAogICJLZXJhdGlub2N5dGUiID0gIiNGRkIzNDciLCAjIFN0cm9uZyBQYXN0ZWwgT3JhbmdlICAKICAiTWVsYW5vY3l0ZSIgPSAiI0ZGRDcwMCIsICAgIyBTdHJvbmcgUGFzdGVsIFllbGxvdyAgCiAgIkVuZG90aGVsaWFsIiA9ICIjNzdERDc3IiwgICMgU3Ryb25nIFBhc3RlbCBHcmVlbiAgCiAgIk5ldXJvbmFsIiA9ICIjNzc5RUNCIiwgICAgICMgU3Ryb25nIFBhc3RlbCBCbHVlICAKICAiTWVzZW5jaHltYWwiID0gIiNDMjdCQTAiICAgIyBTdHJvbmcgUGFzdGVsIFB1cnBsZSAgCikKClJPQ2FuZEFVQ3Bsb3QoY29ycmNvdW50c19tZXJnZSwgCiAgICAgICAgICAgICAgbWV0YWRhdGFfbWVyZ2UsIAogICAgICAgICAgICAgIGNvbmRpdGlvbl92YXIgPSAiQ29uZGl0aW9uIiwgCiAgICAgICAgICAgICAgY2xhc3MgPSAiU2VuZXNjZW50IiwgCiAgICAgICAgICAgICAgZ2VuZXM9YygiQ0RLTjFBIiwgIkNES04yQSIsICJHTEIxIiwiVFA1MyIsIkNDTDIiKSwgCiAgICAgICAgICAgICAgZ3JvdXBfdmFyPSJDZWxsVHlwZSIsCiAgICAgICAgICAgICAgcGxvdF90eXBlID0gImFsbCIsCiAgICAgICAgICAgICAgaGVhdG1hcF9wYXJhbXMgPSBsaXN0KGNvbCA9IGxpc3QoICIjRjlGNEFFIiAsIiNCNDQxNDEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLjUsMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cz1UKSwKICAgICAgICAgICAgICByb2NfcGFyYW1zID0gbGlzdChucm93PTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbD0yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9ycz1jZWxsVHlwZXNfY29sb3JzKSwKICAgICAgICAgICAgICBjb21tb21wbG90X3BhcmFtcyA9IGxpc3Qod2lkdGhzPWMoMC41LDAuNSkpKQoKCmBgYAoKIyMjIENvaGVuJ3MgZAoKYGBge3J9CkNvaGVuREhlYXRtYXAoY29ycmNvdW50c19tZXJnZSwgCiAgICAgICAgICAgICAgbWV0YWRhdGFfbWVyZ2UsIAogICAgICAgICAgICAgIGdlbmVzPWMoIkNES04xQSIsICJDREtOMkEiLCAiR0xCMSIsIlRQNTMiLCJDQ0wyIiksCiAgICAgICAgICAgICAgY29uZGl0aW9uX3ZhciA9ICJDb25kaXRpb24iLCAKICAgICAgICAgICAgICBjbGFzcyA9ICJTZW5lc2NlbnQiLCAKICAgICAgICAgICAgICBncm91cF92YXIgPSAiQ2VsbFR5cGUiLAogICAgICAgICAgICAgIHRpdGxlID0gTlVMTCwKICAgICAgICAgICAgICB3aWR0aFRpdGxlID0gMTYsCiAgICAgICAgICAgICAgaGVhdG1hcF9wYXJhbXMgPSBsaXN0KGNvbCA9IGxpc3QoICIjRjlGNEFFIiAsIiNCNDQxNDEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzPVQpKQpgYGAKCiMjIyBQQ0Egd2l0aCBnZW5lcyBmcm9tIHNpZ25hdHVyZSBvbmx5CgpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00fQoKQ2VsbFR5cGVjb2xzID0gYygKICAiRmlicm9ibGFzdCIgICA9ICIjRkY2OTYxIiwgICAjIFN0cm9uZyBQYXN0ZWwgUmVkICAKICAiS2VyYXRpbm9jeXRlIiA9ICIjRkZCMzQ3IiwgICAjIFN0cm9uZyBQYXN0ZWwgT3JhbmdlICAKICAiTWVsYW5vY3l0ZSIgICA9ICIjRkZENzAwIiwgICAjIFN0cm9uZyBQYXN0ZWwgWWVsbG93ICAKICAiRW5kb3RoZWxpYWwiICA9ICIjNzdERDc3IiwgICAjIFN0cm9uZyBQYXN0ZWwgR3JlZW4gIAogICJOZXVyb25hbCIgICAgID0gIiM3NzlFQ0IiLCAgICMgU3Ryb25nIFBhc3RlbCBCbHVlICAKICAiTWVzZW5jaHltYWwiICA9ICIjQzI3QkEwIiAgICAjIFN0cm9uZyBQYXN0ZWwgUHVycGxlICAKKQoKc2VuY29scyA8LSBjKAogICJTZW5lc2NlbnQiID0gIiNEMzJGMkYiLCAgIyBTdHJvbmcgc2FsbW9uICAKICAiUXVpZXNjZW50IiA9ICIjRkZCNzREIiwgICMgQnJpZ2h0IHBlYWNoICAKICAiUHJvbGlmZXJhdGl2ZSIgPSAiIzk1NzVDRCIgICMgRGVlcCBwYXN0ZWwgcHVycGxlICAKKQoKcGxvdFBDQShkYXRhPWNvcnJjb3VudHNfbWVyZ2UsIAogICAgICAgIG1ldGFkYXRhPW1ldGFkYXRhX21lcmdlLCAKICAgICAgICBnZW5lcz1jKCJDREtOMUEiLCAiQ0RLTjJBIiwgIkdMQjEiLCJUUDUzIiwiQ0NMMiIpLCAKICAgICAgICBzY2FsZT1GQUxTRSwgCiAgICAgICAgY2VudGVyPVRSVUUsIAogICAgICAgIFBDcz1saXN0KGMoMSwyKSwgYygyLDMpLCBjKDMsNCkpLCAKICAgICAgICBDb2xvclZhcmlhYmxlPSJDb25kaXRpb24iLAogICAgICAgIENvbG9yVmFsdWVzPXNlbmNvbHMsCiAgICAgICAgcG9pbnRTaXplPTUsCiAgICAgICAgbGVnZW5kX25yb3c9MSwgCiAgICAgICAgbmNvbD0zLCAKICAgICAgICBucm93PU5VTEwpCmBgYAoKCiMgRW5yaWNobWVudC1iYXNlZAoKIyMgR1NFQQoKCmBgYHtyfQpvcHRpb25zKGVycm9yPXJlY292ZXIpCmRlZ2VuZXMgPC0gY2FsY3VsYXRlREUoZGF0YT1jb3JyY291bnRzX21lcmdlLCAKICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YT1tZXRhZGF0YV9tZXJnZSwgCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGVzPSJDb25kaXRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICBsbWV4cHJlc3Npb24gPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICBtb2RlbG1hdCA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cyA9IGMoIlNlbmVzY2VudCAtIFByb2xpZmVyYXRpdmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlbmVzY2VudCAtIFF1aWVzY2VudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUHJvbGlmZXJhdGl2ZSAtIFF1aWVzY2VudCIpKSAKCmRlZ2VuZXMKYGBgCgpgYGB7ciBmaWcud2lkdGg9MjEsIGZpZy5oZWlnaHQ9Nn0Kb3B0aW9ucyhlcnJvcj1yZWNvdmVyKQpwbG90Vm9sY2FubyhERVJlc3VsdHNMaXN0PWRlZ2VuZXMsIGdlbmVzPWJpZGlyZWN0c2lncywgTj1OVUxMLCB4PSJsb2dGQyIseT0iLWxvZzEwKGFkai5QLlZhbCkiLCBwb2ludFNpemU9MiwgY29sb3I9InBpbmsiLCBoaWdobGlnaHRjb2xvcj0iZGFya2JsdWUiLCBoaWdobGlnaHRjb2xvcl91cHJlZyA9ICIjMDM4QzY1IiwgaGlnaGxpZ2h0Y29sb3JfZG93bnJlZyA9ICIjOEMwMzAzIiwgbm9pbnRlcmVzdGNvbG9yPSJncmV5Iix0aHJlc2hvbGRfeT1OVUxMLCB0aHJlc2hvbGRfeD1OVUxMLCB4bGFiPU5VTEwsIHlsYWI9TlVMTCwgbmNvbD1OVUxMLCBucm93PU5VTEwsIHRpdGxlPU5VTEwsbGFic2l6ZT03LHdpZHRobGFicz0yNSwgaW52ZXJ0PVQpCgpgYGAKIAoKCmBgYHtyfQpHU0VBcmVzdWx0cyA8LSBydW5HU0VBKGRlZ2VuZXMsIGJpZGlyZWN0c2lncywgc3RhdCA9IE5VTEwpCkdTRUFyZXN1bHRzCmBgYAoKCmBgYHtyIGZpZy53aWR0aD0yNSwgZmlnLmhlaWdodD0xMH0KcGxvdEdTRUFlbnJpY2htZW50KEdTRUFfcmVzdWx0cz1HU0VBcmVzdWx0cywgREVHTGlzdD1kZWdlbmVzLCBnZW5lX3NldHM9YmlkaXJlY3RzaWdzLCB3aWR0aFRpdGxlPTMyLGdyaWQgPSBULCB0aXRsZXNpemUgPSAxMCwgbnJvdz0zLCBuY29sPTkpIAoKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9NH0KcGxvdE5FU2xvbGxpcG9wKEdTRUFfcmVzdWx0cz1HU0VBcmVzdWx0cywgc2lnX3RocmVzaG9sZCA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICAgICAgICBsb3dfY29sb3IgPSAiYmx1ZSIsIG1pZF9jb2xvciA9ICJ3aGl0ZSIsIGhpZ2hfY29sb3IgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWQgPSBULCBucm93ID0gMSwgbmNvbCA9IE5VTEwsICAgcGFkal9saW1pdD1jKDAsMC4xKSwgd2lkdGhsYWJlbHM9MjgsIHRpdGxlPU5VTEwpCiAKYGBgCiAKYGBge3J9CnBsb3RDb21iaW5lZEdTRUEoR1NFQXJlc3VsdHMsIHNpZ190aHJlc2hvbGQgPSAwLjA1LCBQb2ludFNpemU9OSwgd2lkdGhsZWdlbmQgPSAyNiApCmBgYAogCiAgCiAKIAojIyBBc3NvY2lhdGlvbiB3aXRoIFBoZW5vdHlwZQoKCklmIHRoZSB1c2VyIGlzIGludmVzdGlnYXRpbmcgaWYgYSBjZXJ0YWluIHZhcmlhYmxlIGNhbiBiZSBkZXNjcmliZWQgZnJvbSB0aGUgR1NFQSByZXN1bHRzLCBhbmQgbm90IGFscmVhZHkga25vd2luZyB0aGF0IHZhcmlhYmxlLiBNb3JlIGV4cGxvcmF0b3J5Li4uCiAKLSBGb3IgZWFjaCB2YXJpYWJsZSwgZGVmaW5lIGFsbCBwb3NzaWJsZSBjb250cmFzdHMgKGUuZy4gaWYgQSxCLEMsIHRoZW4gY29uc2lkZXIgQS1CLCBBLUMsIEItQyxBLShCK0MpLzIsIGV0Yy4uLikKLSBVc2UgY2FsY3VsYXRlREUgd2l0aG91dCBiYXNlbGluZSBhbmQgYWxsIHBvc3NpYmxlIGNvbnRyYXN0cwotIHBlcmZvcm0gR1NFQSBhbmQgY29sbGVjdCBhbGwgcmVzdWx0cyBpbiBvbmx5IG9uZSB0YWJsZQotIFBsb3QgYWxsIHJlc3VsdHMgaW4gbG9sbGlwb3AgcGxvdHMsIHkgYXhpcyB3aXRoIGFsbCBjb250cmFzdHMKCi0gT25lIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSBhbGwgcmVzdWx0czsgb25lIHRvIGRvIHRoZSBsb2xseXBvcCBwbG90CgpgYGB7cn0KIyBFeGFtcGxlIHVzYWdlCmxldmVscyA8LSBjKCJBIiwgIkIiICwiQyIsIkQiKQpnZW5lcmF0ZV9hbGxfY29udHJhc3RzKGxldmVscywgbW9kZT0iZXh0ZW5zaXZlIikKYGBgCgogICAKIAoKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTEwfQogb3B0aW9ucyhlcnJvcj1yZWNvdmVyKQpkZl90ZXN0IDwtIEdTRUFfVmFyaWFibGVBc3NvY2lhdGlvbihkYXRhPWNvcnJjb3VudHNfbWVyZ2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE9bWV0YWRhdGFfbWVyZ2VfY29yciwgCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xzPWMoIkNvbmRpdGlvbiIsIklzX1NlbmVzY2VudCIsInJhbmRvbV9jYXQiLCJyYW5kb21fbnVtZXJpYyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGU9ImV4dGVuc2l2ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9zZXQ9bGlzdChIZXJuYW5kZXpTZWd1cmE9YmlkaXJlY3RzaWdzJEhlcm5hbmRlelNlZ3VyYSksIAogICAgICAgICAgICAgICAgICAgICAgICAgcGFkal9saW1pdCA9IGMoMCwgMC4xKSwgbG93X2NvbG9yID0gImJsdWUiLCBtaWRfY29sb3IgPSAid2hpdGUiLCBoaWdoX2NvbG9yID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2lnX3RocmVzaG9sZCA9IDAuMDUsIHdpZHRobGFiZWxzPTMwLCBsYWJzaXplPTEwLCB0aXRsZXNpemU9MTQpIAoKZGZfdGVzdCRwbG90CgpgYGAKIAogCiAKYGBge3J9Cm1ldGFkYXRhX2NvcnJfMSA8LSBDYWxjdWxhdGVTY29yZXMoZGF0YSA9IGNvcnJjb3VudHNfbWVyZ2UsIG1ldGFkYXRhID0gbWV0YWRhdGFfbWVyZ2UsIG1ldGhvZCA9ICJzc0dTRUEiLCBnZW5lX3NldHMgPSBsaXN0KEhlcm5hbmRlelNlZ3VyYT1iaWRpcmVjdHNpZ3MkSGVybmFuZGV6U2VndXJhKSApCm1ldGFkYXRhX2NvcnIgPC0gbWV0YWRhdGFfY29ycl8xJGBIZXJuYW5kZXpTZWd1cmFgCm1ldGFkYXRhX2NvcnIgPC0gbWVyZ2UobWV0YWRhdGFfY29ycixtZXRhZGF0YV9tZXJnZV9jb3JyWyxjKCJzYW1wbGVJRCIsInJhbmRvbV9jYXQiLCJyYW5kb21fbnVtZXJpYyIsIklzX1NlbmVzY2VudCIpXSwgYnkueD0ic2FtcGxlIiwgYnkueT0ic2FtcGxlSUQiLGFsbC54ID0gVCkKbWV0YWRhdGFfY29ycgpgYGAKCmBgYHtyIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTEwfQogCnBsb3Rfc3RhdF90ZXN0cyhtZXRhZGF0YV9jb3JyLCB0YXJnZXRfdmFyPSJzY29yZSIsIGNvbHMgPSBjKCJDb25kaXRpb24iLCJJc19TZW5lc2NlbnQiLCJyYW5kb21fY2F0IiwicmFuZG9tX251bWVyaWMiKSwKICAgICAgICAgICAgICAgICBkaXNjcmV0ZV9jb2xvcnMgPSBsaXN0KElzX1NlbmVzY2VudD1jKCJTZW5lc2NlbnQiPSJwaW5rIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb24gU2VuZXNjZW50Ij0ib3JhbmdlIikpLCAKICAgICAgICAgICAgICAgIGNvbnRpbnVvdXNfY29sb3IgPSAiIzhDNkQwMyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JfcGFsZXR0ZSA9ICJTZXQyIiwgbnJvdz00LCBzaXplYW5ub3Q9MywgbGVnZW5kLnBvc2l0aW9uPSJ0b3AiKQpgYGAKCgogCgpgYGB7cn0KZGVnZW5lc190ZXN0IDwtIGNhbGN1bGF0ZURFKGRhdGE9Y29ycmNvdW50c19tZXJnZSwgCiAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE9bWV0YWRhdGFfbWVyZ2VfY29yciwgCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGVzPSJyYW5kb21fY2F0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgbG1leHByZXNzaW9uID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxtYXQgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHMgPSBnZW5lcmF0ZV9hbGxfY29udHJhc3RzKGModW5pcXVlKG1ldGFkYXRhX2NvcnIkcmFuZG9tX2NhdCkpLCBtb2RlID0gImV4dGVuc2l2ZSIpKSAKCiAKR1NFQXJlc3VsdHNfdGVzdCA8LSBydW5HU0VBKGRlZ2VuZXNfdGVzdCwgbGlzdChIZXJuYW5kZXpTZWd1cmFfVVA9U2VuZXNjZW5jZVNpZ25hdHVyZXMkYFtVUF1fSGVybmFuZGV6U2VndXJhYCksIHN0YXQgPSBOVUxMKQpHU0VBcmVzdWx0c190ZXN0CiAKb3B0aW9ucyhlcnJvcj1yZWNvdmVyKQpwbG90R1NFQWVucmljaG1lbnQoR1NFQV9yZXN1bHRzPUdTRUFyZXN1bHRzX3Rlc3QsIERFR0xpc3Q9ZGVnZW5lc190ZXN0LCBnZW5lX3NldHM9bGlzdChIZXJuYW5kZXpTZWd1cmFfVVA9U2VuZXNjZW5jZVNpZ25hdHVyZXMkYFtVUF1fSGVybmFuZGV6U2VndXJhYCksIHdpZHRoVGl0bGU9MzIsZ3JpZCA9IEYpIAogCmBgYAoKCiAgCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTV9CiBvcHRpb25zKGVycm9yPXJlY292ZXIpCmRmX3Rlc3QgPC0gR1NFQV9WYXJpYWJsZUFzc29jaWF0aW9uKGRhdGE9Y29ycmNvdW50c19tZXJnZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YT1tZXRhZGF0YV9tZXJnZV9jb3JyLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHM9YygiQ29uZGl0aW9uIiApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGU9Im1lZGl1bSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9zZXQ9bGlzdChIZXJuYW5kZXpTZWd1cmFfVVA9U2VuZXNjZW5jZVNpZ25hdHVyZXMkYFtVUF1fSGVybmFuZGV6U2VndXJhYCApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZGpfbGltaXQgPSBjKDAsIDAuMSksIGxvd19jb2xvciA9ICJibHVlIiwgbWlkX2NvbG9yID0gIndoaXRlIiwgaGlnaF9jb2xvciA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ190aHJlc2hvbGQgPSAwLjA1LCB3aWR0aGxhYmVscz0zMCwgbGFic2l6ZT0xMCwgdGl0bGVzaXplPTE0KSAKCmRmX3Rlc3QkcGxvdAoKZGZfdGVzdCA8LSBHU0VBX1ZhcmlhYmxlQXNzb2NpYXRpb24oZGF0YT1jb3JyY291bnRzX21lcmdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhPW1ldGFkYXRhX21lcmdlX2NvcnIsIAogICAgICAgICAgICAgICAgICAgICAgICAgY29scz1jKCJDb25kaXRpb24iICksIAogICAgICAgICAgICAgICAgICAgICAgICAgbW9kZT0ibWVkaXVtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX3NldD1saXN0KCBIZXJuYW5kZXpTZWd1cmFfVVBfQmlkaXJlY3Q9c3Vic2V0KGJpZGlyZWN0c2lncyRIZXJuYW5kZXpTZWd1cmEsIGVucmljaG1lbnQ9PTEpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWRqX2xpbWl0ID0gYygwLCAwLjEpLCBsb3dfY29sb3IgPSAiYmx1ZSIsIG1pZF9jb2xvciA9ICJ3aGl0ZSIsIGhpZ2hfY29sb3IgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzaWdfdGhyZXNob2xkID0gMC4wNSwgd2lkdGhsYWJlbHM9MzAsIGxhYnNpemU9MTAsIHRpdGxlc2l6ZT0xNCkgCgpkZl90ZXN0JHBsb3QKCgpgYGAK